home *** CD-ROM | disk | FTP | other *** search
/ Delphi 5 for Professionals / DELPHI5.iso / AddOns / Components / Orpheus v3.02 / SETUP.EXE / %MAINDIR% / OvcTable.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1999-02-25  |  204.3 KB  |  6,162 lines

  1. {*********************************************************}
  2. {*                  OVCTABLE.PAS 3.00                    *}
  3. {*     Copyright (c) 1995-99 TurboPower Software Co      *}
  4. {*                 All rights reserved.                  *}
  5. {*********************************************************}
  6.  
  7. {$I OVC.INC}
  8.  
  9. {$B-} {Complete Boolean Evaluation}
  10. {$I+} {Input/Output-Checking}
  11. {$P+} {Open Parameters}
  12. {$T-} {Typed @ Operator}
  13. {$W-} {Windows Stack Frame}
  14. {$X+} {Extended Syntax}
  15.  
  16. {$IFNDEF Win32}
  17. {$G+} {286 Instructions}
  18. {$N+} {Numeric Coprocessor}
  19.  
  20. {$C MOVEABLE,DEMANDLOAD,DISCARDABLE}
  21. {$ENDIF}
  22.  
  23. unit OvcTable;
  24.   {Orpheus table definitions}
  25.  
  26. interface
  27.  
  28. uses
  29.   {$IFDEF Win32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF}
  30.   SysUtils, Messages,
  31.   Graphics, Classes, Controls, Forms, StdCtrls, Menus, Dialogs,
  32.   OvcMisc, OvcData, OvcConst, OvcBase, OvcCmd,
  33.   OvcTCmmn, OvcSpAry, OvcTCAry, OvcTSelL, OvcTCell, OvcTCHdr,
  34.   OvcTGRes, OvcTGPns, OvcTbClr, OvcTbRws, OvcTbCls, OvcDrag;
  35.  
  36. type
  37.   TOvcCustomTable = class(TOvcTableAncestor)
  38.     {-The custom class for tables}
  39.     protected {private}
  40.       {.Z+}
  41.       {property fields - even size}
  42.       FActiveCol      : TColNum;             {column of active cell}
  43.       FActiveRow      : TRowNum;             {row of active cell}
  44.       FBlockColBegin  : TColNum;             {start column for settings}
  45.       FBlockColEnd    : TColNum;             {end column for settings}
  46.       FBlockRowBegin  : TRowNum;             {start row for settings}
  47.       FBlockRowEnd    : TRowNum;             {end row for settings}
  48.       FCells          : TOvcTableCells;      {independent cells}
  49.       FColors         : TOvcTableColors;     {table cell colors}
  50.       FCols           : TOvcTableColumns;    {table column definitions}
  51.       FGridPenSet     : TOvcGridPenSet;      {set of grid pens}
  52.       FLeftCol        : TColNum;             {leftmost column}
  53.       FLockedCols     : TColNum;             {number of locked columns}
  54.       FLockedRows     : TRowNum;             {number of locked rows}
  55.       FLockedRowsCell : TOvcBaseTableCell;   {cell for column headings}
  56.       FRows           : TOvcTableRows;       {table row definitions}
  57.       FSelAnchorCol   : TColNum;             {selection: anchor column}
  58.       FSelAnchorRow   : TRowNum;             {selection: anchor row}
  59.       FTopRow         : TRowNum;             {topmost row}
  60.       FColorUnused    : TColor;              {color of unused area}
  61.  
  62.       {property fields - odd size}
  63.       FAccess      : TOvcTblAccess;          {default access mode for the table}
  64.       FAdjust      : TOvcTblAdjust;          {default adjustment for the table}
  65.       FBorderStyle : TBorderStyle;           {border type around table}
  66.       FOptions     : TOvcTblOptionSet;       {set of table options}
  67.       FScrollBars  : TScrollStyle;           {scroll bar presence}
  68.       Filler       : byte;
  69.  
  70.       {property event fields}
  71.       FActiveCellChanged  : TCellNotifyEvent;       {active cell changed event}
  72.       FActiveCellMoving   : TCellMoveNotifyEvent;   {active cell moving event}
  73.       FBeginEdit          : TCellBeginEditNotifyEvent;{active cell about to be edited}
  74.       FClipboardCopy      : TNotifyEvent;           {copy to clipboard requested}
  75.       FClipboardCut       : TNotifyEvent;           {cut to clipboard requested}
  76.       FClipboardPaste     : TNotifyEvent;           {paste from clipboard requested}
  77.       FColumnsChanged     : TColChangeNotifyEvent;  {column insert/delete/exchange}
  78.       FDoneEdit           : TCellNotifyEvent;       {active cell has been edited}
  79.       FEndEdit            : TCellEndEditNotifyEvent;{active cell about to be stopped being edited}
  80.       FEnteringColumn     : TColNotifyEvent;        {entering column event}
  81.       FEnteringRow        : TRowNotifyEvent;        {entering row event}
  82.       FGetCellData        : TCellDataNotifyEvent;   {get cell data event}
  83.       FGetCellAttributes  : TCellAttrNotifyEvent;   {get cell attributes event}
  84.       FLeavingColumn      : TColNotifyEvent;        {leaving column event}
  85.       FLeavingRow         : TRowNotifyEvent;        {leaving row event}
  86.       FLockedCellClick    : TCellNotifyEvent;       {locked cell clicked event}
  87.       FPaintUnusedArea    : TNotifyEvent;           {unused bit needs painting event}
  88.       FRowsChanged        : TRowChangeNotifyEvent;  {row insert/delete/exchange}
  89.       FSizeCellEditor     : TSizeCellEditorNotifyEvent;{sizing of cell editor}
  90.       FTopLeftCellChanged : TCellNotifyEvent;       {top left cell change event}
  91.       FTopLeftCellChanging: TCellChangeNotifyEvent; {top left cell moving event}
  92.       FUserCommand        : TUserCommandEvent;      {user command event}
  93.  
  94.       {other fields - even size}
  95.       tbColNums : POvcTblDisplayArray;  {displayed column numbers}
  96.       tbRowNums : POvcTblDisplayArray;  {displayed row numbers}
  97.       tbRowsOnLastPage : TRowNum;       {number of complete rows on last page}
  98.       tbLastTopRow : TRowNum;           {the last row number that can be top}
  99.       tbColsOnLastPage : TColNum;       {num of complete columns on rightmost page}
  100.       tbLastLeftCol : TColNum;          {the last column number that can be leftmost}
  101.       tbLockCount : integer;            {the lock display count}
  102.       tbCmdTable : PString;             {the command table name for the grid}
  103.       tbState : TOvcTblStates;          {the state of the table}
  104.       tbSizeOffset : integer;           {the offset of the sizing line}
  105.       tbSizeIndex  : integer;           {the index of the sized row/col}
  106.       tbMoveIndex : integer;            {the index of the column being moved}
  107.       tbMoveIndexTo : integer;          {the index of the column being targeted by move}
  108.       tbLastEntRow : TRowNum;           {last row that was entered}
  109.       tbLastEntCol : TColNum;           {last column that was entered}
  110.       tbActCell : TOvcBaseTableCell;    {the active cell object}
  111.       tbInvCells : TOvcCellArray;       {cells that need repainting}
  112.       tbSelList : TOvcSelectionList;    {list of selected cells}
  113.       tbCellAttrFont : TFont;           {cached font for painting cells}
  114.       tbColMoveCursor : HCursor;        {cursor for column moves}
  115.       tbRowMoveCursor : HCursor;        {cursor for row moves}
  116.       tbHSBarPosCount : integer;        {number of positions for horz scrollbar}
  117.       tbDrag : TOvcDragShow;
  118.  
  119.       {other fields - odd size}
  120.       tbHasHSBar : boolean;             {true if horiz scroll bar present}
  121.       tbHasVSBar : boolean;             {true if vert scroll bar present}
  122.       tbUpdateSBs : boolean;            {true if the scroll bars must be updated}
  123.       tbIsSelecting : boolean;          {is in mouse selection mode}
  124.       tbIsDeselecting : boolean;        {is in mouse deselection mode}
  125.       tbIsKeySelecting : boolean;       {is in key selection mode}
  126.       tbMustUpdate : boolean;           {scrolling has left an invalid region}
  127.       tbMustFinishLoading : boolean;    {finish loading data in CreateWnd}
  128.       {.Z-}
  129.  
  130.     protected
  131.       {.Z+}
  132.       {property read routines}
  133.       function GetAllowRedraw : boolean;
  134.       function GetColCount : TColNum;
  135.       function GetColOffset(ColNum : TColNum) : integer;
  136.       function GetRowLimit : TRowNum;
  137.       function GetRowOffset(RowNum : TRowNum) : integer;
  138.  
  139.       {property write routines}
  140.       procedure SetAccess(A : TOvcTblAccess);
  141.       procedure SetActiveCol(ColNum : TColNum);
  142.       procedure SetActiveRow(RowNum : TRowNum);
  143.       procedure SetAdjust(A : TOvcTblAdjust);
  144.       procedure SetAllowRedraw(AR : boolean);
  145.       procedure SetBorderStyle(const BS : TBorderStyle);
  146.       procedure SetBlockAccess(A : TOvcTblAccess);
  147.       procedure SetBlockAdjust(A : TOvcTblAdjust);
  148.       procedure SetBlockCell(C : TOvcBaseTableCell);
  149.       procedure SetBlockColBegin(ColNum : TColNum);
  150.       procedure SetBlockColEnd(ColNum : TColNum);
  151.       procedure SetBlockColor(C : TColor);
  152.       procedure SetBlockFont(F : TFont);
  153.       procedure SetBlockRowBegin(RowNum : TRowNum);
  154.       procedure SetBlockRowEnd(RowNum : TRowNum);
  155.       procedure SetColors(C : TOvcTableColors);
  156.       procedure SetColCount(CC : integer);
  157.       procedure SetCols(CS : TOvcTableColumns);
  158.       procedure SetLeftCol(ColNum : TColNum);
  159.       procedure SetLockedCols(ColNum : TColNum);
  160.       procedure SetLockedRows(RowNum : TRowNum);
  161.       procedure SetLockedRowsCell(C : TOvcBaseTableCell);
  162.       procedure SetOptions(O : TOvcTblOptionSet);
  163.       procedure SetPaintUnusedArea(PUA : TNotifyEvent);
  164.       procedure SetRowLimit(RowNum : TRowNum);
  165.       procedure SetRows(RS : TOvcTableRows);
  166.       procedure SetScrollBars(const SB : TScrollStyle);
  167.       procedure SetTopRow(RowNum : TRowNum);
  168.       procedure SetColorUnused(CU : TColor);
  169.  
  170.       {overridden Delphi VCL methods}
  171.       procedure ChangeScale(M, D : integer); override;
  172.       procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  173.  
  174.       {general methods}
  175.       function  tbCalcActiveCellRect(var ACR : TRect) : boolean;
  176.       function  tbCalcCellsFromRect(const UR : TRect; var GR : TRect) : integer;
  177.       procedure tbCalcColData(var CD : POvcTblDisplayArray; NewLeftCol : TColNum);
  178.       procedure tbCalcColsOnLastPage;
  179.       procedure tbCalcHSBarPosCount;
  180.       function  tbCalcRequiresVSBar : boolean;
  181.       procedure tbCalcRowData(var RD : POvcTblDisplayArray; NewTopRow : TRowNum);
  182.       procedure tbCalcRowsOnLastPage;
  183.  
  184.       procedure tbDrawActiveCell;
  185.       procedure tbDrawCells(RowInxStart, RowInxEnd : integer;
  186.                             ColInxStart, ColInxEnd : integer);
  187.       procedure tbDrawInvalidCells(InvCells : TOvcCellArray);
  188.       procedure tbDrawMoveLine;
  189.       procedure tbDrawRow(RowInx : integer; ColInxStart, ColInxEnd : integer);
  190.       procedure tbDrawSizeLine;
  191.       procedure tbDrawUnusedBit;
  192.  
  193.       function  tbEditCellHasFocus(FocusHandle : HWND) : boolean;
  194.       procedure tbEnsureColumnIsVisible(ColNum : TColNum);
  195.       procedure tbEnsureRowIsVisible(RowNum : TRowNum);
  196.  
  197.       function  tbFindCell(RowNum : TRowNum;
  198.                            ColNum : TColNum) : TOvcBaseTableCell;
  199.       function  tbFindColInx(ColNum : TColNum) : integer;
  200.       function  tbFindRowInx(RowNum : TRowNum) : integer;
  201.  
  202.       function  tbIsOnGridLine(MouseX, MouseY : integer;
  203.                                var VerticalGrid : boolean) : boolean;
  204.       function  tbIsInMoveArea(MouseX, MouseY : integer;
  205.                            var IsColMove : boolean) : boolean;
  206.       procedure tbSetActiveCellWithSel(RowNum : TRowNum;
  207.                                        ColNum : TColNum);
  208.       procedure tbSetActiveCellPrim(RowNum : TRowNum; ColNum : TColNum);
  209.  
  210.       {selection methods}
  211.       procedure tbDeselectAll(CA : TOvcCellArray);
  212.       function tbDeselectAllIterator(RowNum1 : TRowNum; ColNum1 : TColNum;
  213.                                      RowNum2 : TRowNum; ColNum2 : TColNum;
  214.                                      ExtraData : pointer) : boolean;
  215.       procedure tbSelectCol(ColNum : TColNum);
  216.       procedure tbSelectRow(RowNum : TRowNum);
  217.       procedure tbSelectTable;
  218.       procedure tbSetAnchorCell(RowNum : TRowNum; ColNum : TColNum;
  219.                                 Action : TOvcTblSelectionType);
  220.       procedure tbUpdateSelection(RowNum : TRowNum; ColNum : TColNum;
  221.                                   Action : TOvcTblSelectionType);
  222.  
  223.       {notification procedures}
  224.       procedure DoActiveCellChanged(RowNum : TRowNum; ColNum : TColNum);
  225.         virtual;
  226.       procedure DoActiveCellMoving(Command : word; var RowNum : TRowNum;
  227.                                    var ColNum : TColNum); virtual;
  228.       procedure DoBeginEdit(RowNum : TRowNum; ColNum : TColNum;
  229.                             var AllowIt : boolean); virtual;
  230.       procedure DoClipboardCopy; virtual;
  231.       procedure DoClipboardCut; virtual;
  232.       procedure DoClipboardPaste; virtual;
  233.       procedure DoColumnsChanged(ColNum1, ColNum2 : TColNum;
  234.                                  Action : TOvcTblActions); virtual;
  235.       procedure DoDoneEdit(RowNum : TRowNum; ColNum : TColNum); virtual;
  236.       procedure DoEndEdit(Cell : TOvcBaseTableCell;
  237.                           RowNum : TRowNum; ColNum : TColNum;
  238.                           var AllowIt : boolean); virtual;
  239.       procedure DoEnteringColumn(ColNum : TColNum); virtual;
  240.       procedure DoEnteringRow(RowNum : TRowNum); virtual;
  241.       procedure DoGetCellAttributes(RowNum : TRowNum; ColNum : TColNum;
  242.                                     var CellAttr : TOvcCellAttributes); virtual;
  243.       procedure DoGetCellData(RowNum : TRowNum; ColNum : TColNum;
  244.                               var Data : pointer;
  245.                               Purpose : TOvcCellDataPurpose); virtual;
  246.       procedure DoLeavingColumn(ColNum : TColNum); virtual;
  247.       procedure DoLeavingRow(RowNum : TRowNum); virtual;
  248.       procedure DoLockedCellClick(RowNum : TRowNum; ColNum : TColNum); virtual;
  249.       {$IFDEF WIN32}
  250.       procedure DoOnMouseWheel(Shift : TShiftState; Delta, XPos, YPos : SmallInt);
  251.         override;
  252.       {$ENDIF}
  253.       procedure DoPaintUnusedArea; virtual;
  254.       procedure DoRowsChanged(RowNum1, RowNum2 : TRowNum;
  255.                               Action : TOvcTblActions); virtual;
  256.       procedure DoSizeCellEditor(RowNum   : TRowNum;
  257.                                  ColNum   : TColNum;
  258.                              var CellRect : TRect;
  259.                              var CellStyle: TOvcTblEditorStyle); virtual;
  260.       procedure DoTopLeftCellChanged(RowNum : TRowNum; ColNum : TColNum); virtual;
  261.       procedure DoTopLeftCellChanging(var RowNum : TRowNum;
  262.                                       var ColNum : TColNum); virtual;
  263.       procedure DoUserCommand(Cmd : word); virtual;
  264.  
  265.       {row/col data retrieval}
  266.       function tbIsColHidden(ColNum : TColNum) : boolean;
  267.       function tbIsRowHidden(RowNum : TRowNum) : boolean;
  268.       procedure tbQueryColData(ColNum : TColNum;
  269.                            var W : integer;
  270.                            var A : TOvcTblAccess;
  271.                            var H : boolean);
  272.       procedure tbQueryRowData(RowNum : TRowNum;
  273.                            var Ht: integer;
  274.                            var H : boolean);
  275.  
  276.       {invalidation}
  277.       procedure tbInvalidateColHdgPrim(ColNum : TColNum; InvCells : TOvcCellArray);
  278.       procedure tbInvalidateRowHdgPrim(RowNum : TRowNum; InvCells : TOvcCellArray);
  279.  
  280.       {scrollbar stuff}
  281.       procedure tbSetScrollPos(SB : TOvcScrollBar);
  282.       procedure tbSetScrollRange(SB : TOvcScrollBar);
  283.  
  284.       {active cell movement}
  285.       procedure tbMoveActCellBotOfPage;
  286.       procedure tbMoveActCellBotRight;
  287.       procedure tbMoveActCellDown;
  288.       procedure tbMoveActCellFirstCol;
  289.       procedure tbMoveActCellFirstRow;
  290.       procedure tbMoveActCellLastCol;
  291.       procedure tbMoveActCellLastRow;
  292.       procedure tbMoveActCellLeft;
  293.       procedure tbMoveActCellPageDown;
  294.       procedure tbMoveActCellPageLeft;
  295.       procedure tbMoveActCellPageRight;
  296.       procedure tbMoveActCellPageUp;
  297.       procedure tbMoveActCellRight;
  298.       procedure tbMoveActCellTopLeft;
  299.       procedure tbMoveActCellTopOfPage;
  300.       procedure tbMoveActCellUp;
  301.  
  302.       {scrollbar scrolling routine}
  303.       procedure tbScrollBarDown;
  304.       procedure tbScrollBarLeft;
  305.       procedure tbScrollBarPageDown;
  306.       procedure tbScrollBarPageLeft;
  307.       procedure tbScrollBarPageRight;
  308.       procedure tbScrollBarPageUp;
  309.       procedure tbScrollBarRight;
  310.       procedure tbScrollBarUp;
  311.  
  312.       {table scrolling routines}
  313.       procedure tbScrollTableLeft(NewLeftCol : TColNum);
  314.       procedure tbScrollTableRight(NewLeftCol : TColNum);
  315.       procedure tbScrollTableUp(NewTopRow : TRowNum);
  316.       procedure tbScrollTableDown(NewTopRow : TRowNum);
  317.  
  318.       {notifications}
  319.       procedure tbCellChanged(Sender : TObject); override;
  320.       procedure tbColChanged(Sender : TObject; ColNum1, ColNum2 : TColNum;
  321.                              Action : TOvcTblActions);
  322.       procedure tbGridPenChanged(Sender : TObject);
  323.       procedure tbRowChanged(Sender : TObject; RowNum1, RowNum2 : TRowNum;
  324.                              Action : TOvcTblActions);
  325.       procedure tbColorsChanged(Sender : TObject);
  326.  
  327.       {streaming routines}
  328.       procedure DefineProperties(Filer : TFiler); override;
  329.       procedure tbFinishLoadingDefaultCells;
  330.       procedure tbReadColData(Reader : TReader);
  331.       procedure tbReadRowData(Reader : TReader);
  332.       procedure tbWriteColData(Writer : TWriter);
  333.       procedure tbWriteRowData(Writer : TWriter);
  334.  
  335.       {Cell-Table interaction messages}
  336.       {$IFDEF Win32}
  337.       procedure ctimLoadDefaultCells(var Msg : TMessage); message ctim_LoadDefaultCells;
  338.       {$ENDIF}
  339.       procedure ctimQueryOptions(var Msg : TMessage); message ctim_QueryOptions;
  340.       procedure ctimQueryColor(var Msg : TMessage); message ctim_QueryColor;
  341.       procedure ctimQueryFont(var Msg : TMessage); message ctim_QueryFont;
  342.       procedure ctimQueryLockedCols(var Msg : TMessage); message ctim_QueryLockedCols;
  343.       procedure ctimQueryLockedRows(var Msg : TMessage); message ctim_QueryLockedRows;
  344.       procedure ctimQueryActiveCol(var Msg : TMessage); message ctim_QueryActiveCol;
  345.       procedure ctimQueryActiveRow(var Msg : TMessage); message ctim_QueryActiveRow;
  346.       procedure ctimRemoveCell(var Msg : TMessage); message ctim_RemoveCell;
  347.       procedure ctimStartEdit(var Msg : TMessage); message ctim_StartEdit;
  348.       procedure ctimStartEditMouse(var Msg : TWMMouse); message ctim_StartEditMouse;
  349.       procedure ctimStartEditKey(var Msg : TWMKey); message ctim_StartEditKey;
  350.  
  351.       {Delphi component messages}
  352.       procedure CMColorChanged(var Msg : TMessage); message CM_COLORCHANGED;
  353.       procedure CMCtl3DChanged(var Msg : TMessage); message CM_CTL3DCHANGED;
  354.       procedure CMDesignHitTest(var Msg : TCMDesignHitTest); message CM_DESIGNHITTEST;
  355.       procedure CMFontChanged(var Msg : TMessage); message CM_FONTCHANGED;
  356.  
  357.       {Windows messages}
  358.       procedure WMCancelMode(var Msg : TMessage); message WM_CANCELMODE;
  359.       procedure WMEraseBkGnd(var Msg : TWMEraseBkGnd); message WM_ERASEBKGND;
  360.       procedure WMGetDlgCode(var Msg : TMessage); message WM_GETDLGCODE;
  361.       procedure WMHScroll(var Msg : TWMScroll); message WM_HSCROLL;
  362.       procedure WMKeyDown(var Msg : TWMKey); message WM_KEYDOWN;
  363.       procedure WMKillFocus(var Msg : TWMKillFocus); message WM_KILLFOCUS;
  364.       procedure WMLButtonDblClk(var Msg : TWMMouse); message WM_LBUTTONDBLCLK;
  365.       procedure WMLButtonDown(var Msg : TWMMouse); message WM_LBUTTONDOWN;
  366.       procedure WMLButtonUp(var Msg : TWMMouse); message WM_LBUTTONUP;
  367.       procedure WMMouseMove(var Msg : TWMMouse); message WM_MOUSEMOVE;
  368.       procedure WMNCHitTest(var Msg : TMessage); message WM_NCHITTEST;
  369.       procedure WMSetCursor(var Msg : TWMSetCursor); message WM_SETCURSOR;
  370.       procedure WMSetFocus(var Msg : TWMSetFocus); message WM_SETFOCUS;
  371.       procedure WMVScroll(var Msg : TWMScroll); message WM_VSCROLL;
  372.       {.Z-}
  373.  
  374.       {unpublishable or should not be published properties}
  375.       property AllowRedraw : boolean
  376.          read GetAllowRedraw write SetAllowRedraw
  377.          stored false;
  378.  
  379.       property BlockAccess : TOvcTblAccess
  380.          write SetBlockAccess;
  381.  
  382.       property BlockAdjust : TOvcTblAdjust
  383.          write SetBlockAdjust;
  384.  
  385.       property BlockColBegin : TColNum
  386.          read FBlockColBegin write SetBlockColBegin;
  387.  
  388.       property BlockColEnd : TColNum
  389.          read FBlockColEnd write SetBlockColEnd;
  390.  
  391.       property BlockColor : TColor
  392.          write SetBlockColor;
  393.  
  394.       property BlockCell : TOvcBaseTableCell
  395.          write SetBlockCell;
  396.  
  397.       property BlockFont : TFont
  398.          write SetBlockFont;
  399.  
  400.       property BlockRowBegin : TRowNum
  401.          read FBlockRowBegin write SetBlockRowBegin;
  402.  
  403.       property BlockRowEnd : TRowNum
  404.          read FBlockRowEnd write SetBlockRowEnd;
  405.  
  406.       property ColOffset [ColNum : TColNum] : integer
  407.          read GetColOffset;
  408.  
  409.       property RowOffset [RowNum : TRowNum] : integer
  410.          read GetRowOffset;
  411.  
  412.       property TableState : TOvcTblStates
  413.          read tbState;
  414.  
  415.       {publishable properties}
  416.       property Access : TOvcTblAccess
  417.          read FAccess write SetAccess;
  418.  
  419.       property ActiveCol : TColNum
  420.          read FActiveCol write SetActiveCol;
  421.  
  422.       property ActiveRow : TRowNum
  423.          read FActiveRow write SetActiveRow;
  424.  
  425.       property Adjust : TOvcTblAdjust
  426.          read FAdjust write SetAdjust;
  427.  
  428.       property BorderStyle : TBorderStyle
  429.          read FBorderStyle write SetBorderStyle;
  430.  
  431.       property ColCount : TColNum
  432.          read GetColCount write SetColCount;
  433.  
  434.       property Colors : TOvcTableColors
  435.          read FColors write SetColors;
  436.  
  437.       property ColorUnused : TColor
  438.          read FColorUnused write SetColorUnused;
  439.  
  440.       property Columns : TOvcTableColumns
  441.          read FCols write SetCols;
  442.  
  443.       property GridPenSet : TOvcGridPenSet
  444.          read FGridPenSet write FGridPenSet;
  445.  
  446.       property LeftCol : TColNum
  447.          read FLeftCol write SetLeftCol;
  448.  
  449.       property LockedCols : TColNum
  450.          read FLockedCols write SetLockedCols;
  451.  
  452.       property LockedRows : TRowNum
  453.          read FLockedRows write SetLockedRows;
  454.  
  455.       property LockedRowsCell : TOvcBaseTableCell
  456.          read FLockedRowsCell write SetLockedRowsCell;
  457.  
  458.       property Options : TOvcTblOptionSet
  459.          read FOptions write SetOptions;
  460.  
  461.       property RowLimit : TRowNum
  462.          read GetRowLimit write SetRowLimit;
  463.  
  464.       property Rows : TOvcTableRows
  465.          read FRows write SetRows;
  466.  
  467.       property ScrollBars : TScrollStyle
  468.          read FScrollBars write SetScrollBars;
  469.  
  470.       property TopRow : TRowNum
  471.          read FTopRow write SetTopRow;
  472.  
  473.       {New events}
  474.       property OnActiveCellChanged : TCellNotifyEvent
  475.          read FActiveCellChanged write FActiveCellChanged;
  476.  
  477.       property OnActiveCellMoving : TCellMoveNotifyEvent
  478.          read FActiveCellMoving write FActiveCellMoving;
  479.  
  480.       property OnBeginEdit : TCellBeginEditNotifyEvent
  481.          read FBeginEdit write FBeginEdit;
  482.  
  483.       property OnClipboardCopy : TNotifyEvent
  484.          read FClipboardCopy write FClipboardCopy;
  485.  
  486.       property OnClipboardCut : TNotifyEvent
  487.          read FClipboardCut write FClipboardCut;
  488.  
  489.       property OnClipboardPaste : TNotifyEvent
  490.          read FClipboardPaste write FClipboardPaste;
  491.  
  492.       property OnColumnsChanged : TColChangeNotifyEvent
  493.          read FColumnsChanged write FColumnsChanged;
  494.  
  495.       property OnDoneEdit : TCellNotifyEvent
  496.          read FDoneEdit write FDoneEdit;
  497.  
  498.       property OnEndEdit : TCellEndEditNotifyEvent
  499.          read FEndEdit write FEndEdit;
  500.  
  501.       property OnEnteringColumn : TColNotifyEvent
  502.          read FEnteringColumn write FEnteringColumn;
  503.  
  504.       property OnEnteringRow : TRowNotifyEvent
  505.          read FEnteringRow write FEnteringRow;
  506.  
  507.       property OnGetCellData : TCellDataNotifyEvent
  508.          read FGetCellData write FGetCellData;
  509.  
  510.       property OnGetCellAttributes : TCellAttrNotifyEvent
  511.          read FGetCellAttributes write FGetCellAttributes;
  512.  
  513.       property OnLeavingColumn : TColNotifyEvent
  514.          read FLeavingColumn write FLeavingColumn;
  515.  
  516.       property OnLeavingRow : TRowNotifyEvent
  517.          read FLeavingRow write FLeavingRow;
  518.  
  519.       property OnLockedCellClick : TCellNotifyEvent
  520.          read FLockedCellClick write FLockedCellClick;
  521.  
  522.       property OnPaintUnusedArea : TNotifyEvent
  523.          read FPaintUnusedArea write SetPaintUnusedArea;
  524.  
  525.       property OnRowsChanged : TRowChangeNotifyEvent
  526.          read FRowsChanged write FRowsChanged;
  527.  
  528.       property OnSizeCellEditor : TSizeCellEditorNotifyEvent
  529.          read FSizeCellEditor write FSizeCellEditor;
  530.  
  531.       property OnTopLeftCellChanged : TCellNotifyEvent
  532.          read FTopLeftCellChanged write FTopLeftCellChanged;
  533.  
  534.       property OnTopLeftCellChanging : TCellChangeNotifyEvent
  535.          read FTopLeftCellChanging write FTopLeftCellChanging;
  536.  
  537.       property OnUserCommand : TUserCommandEvent
  538.          read FUserCommand write FUserCommand;
  539.  
  540.     public
  541.       {overridden methods}
  542.       constructor Create(AOwner : TComponent); override;
  543.       destructor Destroy; override;
  544.       procedure CreateParams(var Params : TCreateParams); override;
  545.       procedure CreateWnd; override;
  546.       procedure Loaded; override;
  547.       procedure Paint; override;
  548.       procedure SetBounds(ALeft, ATop, AWidth, AHeight: integer); override;
  549.  
  550.       {new public methods}
  551.       function CalcRowColFromXY(X, Y : integer;
  552.                                 var RowNum : TRowNum;
  553.                                 var ColNum : TColNum) : TOvcTblRegion;
  554.       function FilterKey(var Msg : TWMKey) : TOvcTblKeyNeeds; override;
  555.       procedure GetDisplayedColNums(var NA : TOvcTableNumberArray);
  556.       procedure GetDisplayedRowNums(var NA : TOvcTableNumberArray);
  557.       procedure ResolveCellAttributes(RowNum : TRowNum; ColNum : TColNum;
  558.                                       var CellAttr : TOvcCellAttributes); override;
  559.  
  560.       {methods for setting cells, faster than setting row/col properties}
  561.       procedure SetActiveCell(RowNum : TRowNum; ColNum : TColNum);
  562.       procedure SetTopLeftCell(RowNum : TRowNum; ColNum : TColNum);
  563.  
  564.       {methods for calculating next/prev row/col numbers for main area}
  565.       function IncCol(ColNum : TColNum; Direction : integer) : TColNum;
  566.       function IncRow(RowNum : TRowNum; Direction : integer) : TRowNum;
  567.  
  568.       {methods for invalidating cells to force a redraw}
  569.       procedure InvalidateCell(RowNum : TRowNum; ColNum : TColNum);
  570.       procedure InvalidateColumn(ColNum : TColNum);
  571.       procedure InvalidateRow(RowNum : TRowNum);
  572.       procedure InvalidateTable;
  573.       {.Z+}
  574.       procedure InvalidateCellsInRect(const R : TRect);
  575.       procedure InvalidateColumnHeading(ColNum : TColNum);
  576.       procedure InvalidateRowHeading(RowNum : TRowNum);
  577.       procedure InvalidateTableNotLockedCols;
  578.       procedure InvalidateTableNotLockedRows;
  579.       {.Z-}
  580.  
  581.       {selection methods}
  582.       function HaveSelection : boolean;
  583.       function InSelection(RowNum : TRowNum; ColNum : TColNum) : boolean;
  584.       procedure IterateSelections(SI : TSelectionIterator; ExtraData : pointer);
  585.  
  586.       {editing state method}
  587.       function InEditingState : boolean;
  588.       function SaveEditedData : boolean;
  589.       function StartEditingState : boolean;
  590.       function StopEditingState(SaveValue : boolean) : boolean;
  591.  
  592.       {scrollbar scrolling routine}
  593.       procedure ProcessScrollBarClick(ScrollBar : TOvcScrollBar;
  594.                                       ScrollCode : TScrollCode); virtual;
  595.  
  596.       {active cell movement routine}
  597.       procedure MoveActiveCell(Command : word); virtual;
  598.  
  599.       {public property}
  600.       property Cells : TOvcTableCells
  601.          read FCells;
  602.  
  603.  
  604.     end;
  605.  
  606.   TOvcTable = class(TOvcCustomTable)
  607.     public
  608.       property AllowRedraw;
  609.       property BlockAccess;
  610.       property BlockAdjust;
  611.       property BlockColBegin;
  612.       property BlockColEnd;
  613.       property BlockColor;
  614.       property BlockCell;
  615.       property BlockFont;
  616.       property BlockRowBegin;
  617.       property BlockRowEnd;
  618.       property Canvas;
  619.       property ColOffset;
  620.       property RowOffset;
  621.       property TableState;
  622.     published
  623.       {Properties}
  624.       property RowLimit;
  625.       property LockedRows;
  626.       property TopRow;
  627.       property ActiveRow;
  628.  
  629.       property LockedCols;
  630.       property LeftCol;
  631.       property ActiveCol;
  632.  
  633.       {$IFDEF VERSION4}
  634.       property Anchors;
  635.       property Constraints;
  636.       property DragKind;
  637.       {$ENDIF}
  638.       property Access;
  639.       property Adjust;
  640.       property Align;
  641.       property BorderStyle;
  642.       property ColCount stored false; {it's stored elsewhere}
  643.       property Color;
  644.       property ColorUnused;
  645.       property Colors;
  646.       property Columns;
  647.       property Controller;
  648.       property Ctl3D;
  649.       property DragCursor;
  650.       property DragMode;
  651.       property Enabled;
  652.       property Font;
  653.       property GridPenSet;
  654.       property LockedRowsCell;
  655.       property Options;
  656.       property ParentColor;
  657.       property ParentCtl3D;
  658.       property ParentFont;
  659.       property ParentShowHint;
  660.       property PopupMenu;
  661.       property Rows;
  662.       property ScrollBars;
  663.       property ShowHint;
  664.       property TabOrder;
  665.       property TabStop;
  666.       property Visible;
  667.  
  668.       {Events}
  669.       property OnActiveCellChanged;
  670.       property OnActiveCellMoving;
  671.       property OnBeginEdit;
  672.       property OnClipboardCopy;
  673.       property OnClipboardCut;
  674.       property OnClipboardPaste;
  675.       property OnColumnsChanged;
  676.       property OnDblClick;
  677.       property OnDoneEdit;
  678.       property OnDragDrop;
  679.       property OnDragOver;
  680.       property OnEndDrag;
  681.       property OnEndEdit;
  682.       property OnEnter;
  683.       property OnEnteringColumn;
  684.       property OnEnteringRow;
  685.       property OnExit;
  686.       property OnGetCellData;
  687.       property OnGetCellAttributes;
  688.       property OnKeyDown;
  689.       property OnKeyPress;
  690.       property OnKeyUp;
  691.       property OnLeavingColumn;
  692.       property OnLeavingRow;
  693.       property OnLockedCellClick;
  694.       property OnMouseDown;
  695.       property OnMouseMove;
  696.       property OnMouseUp;
  697.       property OnPaintUnusedArea;
  698.       property OnRowsChanged;
  699.       property OnSizeCellEditor;
  700.       property OnTopLeftCellChanged;
  701.       property OnTopLeftCellChanging;
  702.       property OnUserCommand;
  703.     end;
  704.  
  705. implementation
  706.  
  707.  
  708. {==TOvcTable creation and destruction================================}
  709. constructor TOvcCustomTable.Create(AOwner : TComponent);
  710.   begin
  711.     inherited Create(AOwner);
  712.  
  713.     tbState := [otsNormal];
  714.  
  715.     {$IFDEF Win32}
  716.     if NewStyleControls then
  717.       ControlStyle := ControlStyle + [csOpaque, csCaptureMouse, csDoubleClicks]
  718.     else
  719.       ControlStyle := ControlStyle + [csOpaque, csCaptureMouse, csDoubleClicks, csFramed];
  720.     {$ELSE}
  721.       ControlStyle := ControlStyle + [csOpaque, csCaptureMouse, csDoubleClicks, csFramed];
  722.     {$ENDIF}
  723.  
  724.     Height  := tbDefHeight;
  725.     Width   := tbDefWidth;
  726.     FColorUnused := clWindow;
  727.     ParentColor := false;
  728.     Color := tbDefTableColor;
  729.     TabStop := true;
  730.  
  731.     FGridPenSet := TOvcGridPenSet.Create;
  732.     FGridPenSet.OnCfgChanged := tbGridPenChanged;
  733.  
  734.     FColors := TOvcTableColors.Create;
  735.     FColors.OnCfgChanged := tbColorsChanged;
  736.  
  737.     FCols := TOvcTableColumns.Create(Self, tbDefColCount, TOvcTableColumn);
  738.     FCols.OnColumnChanged := tbColChanged;
  739.     FCols.Table := Self;
  740.  
  741.     FCells := TOvcTableCells.Create(Self);
  742.     FCells.OnCfgChanged := tbCellChanged;
  743.     FCells.Table := Self;
  744.     tbInvCells := TOvcCellArray.Create;
  745.  
  746.     FRows := TOvcTableRows.Create;
  747.     RowLimit := tbDefRowCount;
  748.     FRows.OnCfgChanged := tbRowChanged;
  749.  
  750.     FBorderStyle := tbDefBorderStyle;
  751.     FScrollBars := tbDefScrollBars;
  752.     FAccess := tbDefAccess;
  753.     FAdjust := tbDefAdjust;
  754.     tbCellAttrFont := TFont.Create;
  755.  
  756.     FActiveCol := tbDefLockedCols;
  757.     FLockedCols := tbDefLockedCols;
  758.     FLeftCol := tbDefLockedCols;
  759.     FSelAnchorCol := tbDefLockedCols;
  760.  
  761.     FActiveRow := tbDefLockedRows;
  762.     FLockedRows := tbDefLockedRows;
  763.     FTopRow := tbDefLockedRows;
  764.     FSelAnchorRow := tbDefLockedRows;
  765.  
  766.     tbColMoveCursor := LoadBaseCursor('ORCOLUMNMOVECURSOR');
  767.     tbRowMoveCursor := LoadBaseCursor('ORROWMOVECURSOR');
  768.  
  769.     tbSelList := TOvcSelectionList.Create(tbDefRowCount, tbDefColCount);
  770.  
  771.     tbLastEntRow := -1;
  772.     tbLastEntCol := -1;
  773.  
  774.     tbCmdTable := NewStr(GetOrphStr(SCGridTableName));
  775.  
  776.     AssignDisplayArray(tbColNums, succ(tbDefColCount));
  777.     AssignDisplayArray(tbRowNums, succ(tbDefRowCount));
  778.  
  779.     if csDesigning in ComponentState then
  780.       tbState := tbState + [otsDesigning]
  781.     else
  782.       tbState := tbState + [otsUnfocused];
  783.  
  784.     tbMustFinishLoading := true;
  785.   end;
  786. {--------}
  787. destructor TOvcCustomTable.Destroy;
  788.   begin
  789.     if not (csDestroying in ComponentState) then
  790.       Destroying;
  791.     FCols.Free;
  792.     FCells.Free;
  793.     FRows.Free;
  794.     tbInvCells.Free;
  795.     tbSelList.Free;
  796.     tbCellAttrFont.Free;
  797.     if Assigned(tbColNums) then
  798.       AssignDisplayArray(tbColNums, 0);
  799.     if Assigned(tbRowNums) then
  800.       AssignDisplayArray(tbRowNums, 0);
  801.     DisposeStr(tbCmdTable);
  802.     GridPenSet.Free;
  803.     FColors.Free;
  804.  
  805.     inherited Destroy;
  806.   end;
  807. {--------}
  808. procedure TOvcCustomTable.CreateParams(var Params: TCreateParams);
  809.   begin
  810.     inherited CreateParams(Params);
  811.  
  812.     with Params do
  813.       Style := LongInt(Style) or OvcData.ScrollBarStyles[FScrollBars]
  814.                      or OvcData.BorderStyles[FBorderStyle];
  815.  
  816.     {$IFDEF Win32}
  817.     if NewStyleControls and Ctl3D and (FBorderStyle = bsSingle) then begin
  818.       Params.Style := Params.Style and not WS_BORDER;
  819.       Params.ExStyle := Params.ExStyle or WS_EX_CLIENTEDGE;
  820.     end;
  821.     {$ENDIF}
  822.   end;
  823. {--------}
  824. procedure TOvcCustomTable.CreateWnd;
  825.   begin
  826.     inherited CreateWnd;
  827.     {$IFDEF Win32}
  828.     {post a message to ourselves to finish loading the cells}
  829.     {--the reason for this is that cell components _may_ be }
  830.     {  on a data module: we must wait until all data modules}
  831.     {  have been created, otherwise we may not pick up some }
  832.     {  cell references (Delphi 2 does not guarantee any     }
  833.     {  particular order for form/data module creation).     }
  834.     PostMessage(Handle, ctim_LoadDefaultCells, 0, 0);
  835.     {$ENDIF}
  836.  
  837.     tbLockCount := 0;
  838.  
  839.     tbHasHSBar := false;
  840.     tbHasVSBar := false;
  841.     if (FScrollBars = ssBoth) or (FScrollBars = ssHorizontal) then
  842.       tbHasHSBar := true;
  843.     if (FScrollBars = ssBoth) or (FScrollBars = ssVertical) then
  844.       tbHasVSBar := true;
  845.  
  846.     tbCalcColData(tbColNums, LeftCol);
  847.     tbCalcRowData(tbRowNums, TopRow);
  848.     {make sure the column/row properties are valid}
  849.     LeftCol := LeftCol;
  850.     TopRow := TopRow;
  851.     ActiveCol := ActiveCol;
  852.     ActiveRow := ActiveRow;
  853.     FSelAnchorCol := ActiveCol;
  854.     FSelAnchorRow := ActiveRow;
  855.  
  856.     {Set up the scrollbars}
  857.     tbSetScrollRange(otsbHorizontal);
  858.     tbSetScrollPos(otsbHorizontal);
  859.     tbSetScrollRange(otsbVertical);
  860.     tbSetScrollPos(otsbVertical);
  861.  
  862.     {Must trigger the active cell and topleft cell change events}
  863.     DoTopLeftCellChanged(TopRow, LeftCol);
  864.     DoActiveCellChanged(ActiveRow, ActiveCol);
  865.  
  866.     if not (otsDesigning in tbState) and (otoAlwaysEditing in Options) then
  867.       PostMessage(Handle, ctim_StartEdit, 0, 0);
  868.   end;
  869. {--------}
  870. procedure TOvcCustomTable.Loaded;
  871.   begin
  872.     inherited Loaded;
  873.     {$IFNDEF Win32}
  874.     tbFinishLoadingDefaultCells;
  875.     tbSelList.SetColCount(ColCount);
  876.     tbSelList.SetRowCount(RowLimit);
  877.     {$ENDIF}
  878.   end;
  879. {====================================================================}
  880.  
  881.  
  882. {==TOvcTable property streaming routines=============================}
  883. procedure TOvcCustomTable.DefineProperties(Filer : TFiler);
  884.   begin
  885.     inherited DefineProperties(Filer);
  886.     with Filer do
  887.       begin
  888.         DefineProperty('RowData', tbReadRowData, tbWriteRowData, true);
  889.         DefineProperty('ColData', tbReadColData, tbWriteColData, true);
  890.       end;
  891.   end;
  892. {--------}
  893. procedure TOvcCustomTable.tbFinishLoadingDefaultCells;
  894.   var
  895.     i : integer;
  896.   begin
  897.     FCols.tcStopLoading;
  898.     {if our cell list is empty refresh it now}
  899.     if (taCellList.Count = 0) then
  900.       begin
  901.         if Assigned(FLockedRowsCell) then
  902.           tbIncludeCell(FLockedRowsCell);
  903.         for i := 0 to pred(FCols.Count) do
  904.           tbIncludeCell(FCols.DefaultCell[i]);
  905.         {we don't have to do the Cells matrix: no design time support}
  906.       end;
  907.   end;
  908. {--------}
  909. procedure TOvcCustomTable.tbReadColData(Reader : TReader);
  910.   var
  911.     ColObj   : TOvcTableColumn;
  912.     Fixups   : TStringList;
  913.   begin
  914.     AllowRedraw := false;
  915.     with Reader do
  916.       begin
  917.         ReadListBegin;
  918.         FCols.Clear;
  919.         Fixups := FCols.tcStartLoading;
  920.         while not EndOfList do
  921.           begin
  922.             ColObj := TOvcTableColumn.Create(Self);
  923.             ColObj.Width := Readinteger;
  924.             ColObj.Hidden := ReadBoolean;
  925.             if ReadBoolean then
  926.               Fixups.AddObject(ReadString, ColObj);
  927.             FCols.Append(ColObj);
  928.           end;
  929.         ReadListEnd;
  930.       end;
  931.     AllowRedraw := true;
  932.   end;
  933. {--------}
  934. procedure TOvcCustomTable.tbReadRowData(Reader : TReader);
  935.   var
  936.     RowNum   : TRowNum;
  937.     RS       : TRowStyle;
  938.   begin
  939.     with Reader do
  940.       begin
  941.         ReadListBegin;
  942.         FRows.Clear;
  943.         FRows.DefaultHeight := Readinteger;
  944.         while not EndOfList do
  945.           begin
  946.             RowNum := Readinteger;
  947.             RS.Hidden := ReadBoolean;
  948.             RS.Height := Readinteger;
  949.             FRows[RowNum] := RS;
  950.           end;
  951.         ReadListEnd;
  952.       end;
  953.   end;
  954. {--------}
  955. procedure TOvcCustomTable.tbWriteColData(Writer : TWriter);
  956.   var
  957.     ColNum : TColNum;
  958.     S : string;
  959.   begin
  960.     if tbMustFinishLoading then begin
  961.       tbFinishLoadingCellList;
  962.       tbFinishLoadingDefaultCells;
  963.       tbMustFinishLoading := false;
  964.     end;
  965.  
  966.     with Writer do
  967.       begin
  968.         WriteListBegin;
  969.         for ColNum := 0 to pred(ColCount) do
  970.           with FCols[ColNum] do
  971.             begin
  972.               WriteInteger(Width);
  973.               WriteBoolean(Hidden);
  974.               if (DefaultCell <> nil) then
  975.                 begin
  976.                   WriteBoolean(true);
  977.                   {$IFDEF Win32}
  978.                   S := DefaultCell.Owner.Name;
  979.                   if (S <> '') then
  980.                     S := S + '.' + DefaultCell.Name
  981.                   else
  982.                     S := DefaultCell.Name;
  983.                   WriteString(S);
  984.                   {$ELSE}
  985.                   WriteString(DefaultCell.Name);
  986.                   {$ENDIF}
  987.                 end
  988.               else
  989.                 WriteBoolean(false);
  990.             end;
  991.         WriteListEnd;
  992.       end;
  993.   end;
  994. {--------}
  995. procedure TOvcCustomTable.tbWriteRowData(Writer : TWriter);
  996.   var
  997.     RowNum   : TRowNum;
  998.     RS       : TRowStyle;
  999.   begin
  1000.     with Writer do
  1001.       begin
  1002.         WriteListBegin;
  1003.         Writeinteger(FRows.DefaultHeight);
  1004.         for RowNum := 0 to pred(FRows.Limit) do
  1005.           if FRows.RowIsSpecial[RowNum] then
  1006.             begin
  1007.               Writeinteger(RowNum);
  1008.               RS := FRows[RowNum];
  1009.               WriteBoolean(RS.Hidden);
  1010.               Writeinteger(RS.Height);
  1011.             end;
  1012.         WriteListEnd;
  1013.       end;
  1014.   end;
  1015. {====================================================================}
  1016.  
  1017.  
  1018. {==TOvcTable property read routines==================================}
  1019. function TOvcCustomTable.GetAllowRedraw : boolean;
  1020.   begin
  1021.     Result := (tbLockCount = 0);
  1022.   end;
  1023. {--------}
  1024. function TOvcCustomTable.GetColCount : TColNum;
  1025.   begin
  1026.     Result := FCols.Count;
  1027.   end;
  1028. {--------}
  1029. function TOvcCustomTable.GetColOffset(ColNum : TColNum) : integer;
  1030.   var
  1031.     ColInx : integer;
  1032.   begin
  1033.     ColInx := tbFindColInx(ColNum);
  1034.     if (ColInx <> -1) then
  1035.       Result := tbColNums^.Ay[ColInx].Offset
  1036.     else
  1037.       Result := -1;
  1038.   end;
  1039. {--------}
  1040. function TOvcCustomTable.GetRowLimit : TRowNum;
  1041.   begin
  1042.     Result := FRows.Limit;
  1043.   end;
  1044. {--------}
  1045. function TOvcCustomTable.GetRowOffset(RowNum : TRowNum) : integer;
  1046.   var
  1047.     RowInx : integer;
  1048.   begin
  1049.     RowInx := tbFindRowInx(RowNum);
  1050.     if (RowInx <> -1) then
  1051.       Result := tbRowNums^.Ay[RowInx].Offset
  1052.     else
  1053.       Result := -1;
  1054.   end;
  1055. {--------}
  1056. procedure TOvcCustomTable.ResolveCellAttributes(RowNum : TRowNum; ColNum : TColNum;
  1057.                                             var CellAttr : TOvcCellAttributes);
  1058.   var
  1059.     TempAccess    : TOvcTblAccess;
  1060.     TempAdjust    : TOvcTblAdjust;
  1061.     TempColor     : TColor;
  1062.     TempFontColor : TColor;
  1063.     TempSparseAttr: TOvcSparseAttr;
  1064.   begin
  1065.     FCells.ResolveFullAttr(RowNum, ColNum, TempSparseAttr);
  1066.     with CellAttr do
  1067.       begin
  1068.         {calculate the access rights}
  1069.         TempAccess := TempSparseAttr.scaAccess;
  1070.         if (TempAccess = otxDefault) then
  1071.           begin
  1072.             TempAccess := caAccess;
  1073.             if (TempAccess = otxDefault) then
  1074.               TempAccess := Access;
  1075.           end;
  1076.         caAccess := TempAccess;
  1077.         {calculate the adjustment}
  1078.         TempAdjust := TempSparseAttr.scaAdjust;
  1079.         if (TempAdjust = otaDefault) then
  1080.           begin
  1081.             TempAdjust := caAdjust;
  1082.             if (TempAdjust = otaDefault) then
  1083.               TempAdjust := Adjust;
  1084.           end;
  1085.         caAdjust := TempAdjust;
  1086.         {calculate the font}
  1087.         if Assigned(TempSparseAttr.scaFont) then
  1088.           caFont.Assign(TempSparseAttr.scaFont);
  1089.         {calculate the colors}
  1090.         if (RowNum = ActiveRow) and (ColNum = ActiveCol) then
  1091.           if (otsFocused in tbState) then
  1092.             if InEditingState or
  1093.                ((otoAlwaysEditing in Options) and (caAccess = otxNormal)) then
  1094.               begin
  1095.                 TempColor := Colors.Editing;
  1096.                 TempFontColor := Colors.EditingText
  1097.               end
  1098.             else
  1099.               begin
  1100.                 TempColor := Colors.ActiveFocused;
  1101.                 TempFontColor := Colors.ActiveFocusedText;
  1102.               end
  1103.           else
  1104.             begin
  1105.               TempColor := Colors.ActiveUnfocused;
  1106.               TempFontColor := Colors.ActiveUnfocusedText;
  1107.             end
  1108.         else
  1109.           begin
  1110.             if (RowNum = ActiveRow) and (otoBrowseRow in FOptions) then
  1111.               if (otsFocused in tbState) then
  1112.                 begin
  1113.                   TempColor := Colors.ActiveFocused;
  1114.                   TempFontColor := Colors.ActiveFocusedText;
  1115.                 end
  1116.               else
  1117.                 begin
  1118.                   TempColor := Colors.ActiveUnfocused;
  1119.                   TempFontColor := Colors.ActiveUnfocusedText;
  1120.                 end
  1121.             else if InSelection(RowNum, ColNum) then
  1122.               begin
  1123.                 TempColor := Colors.Selected;
  1124.                 TempFontColor := Colors.SelectedText;
  1125.               end
  1126.             else
  1127.               begin
  1128.                 TempColor := TempSparseAttr.scaColor;
  1129.                 if Assigned(TempSparseAttr.scaFont) then
  1130.                   TempFontColor := TempSparseAttr.scaFont.Color
  1131.                 else if (RowNum < LockedRows) or (ColNum < LockedCols) then
  1132.                   TempFontColor := Colors.LockedText
  1133.                 else
  1134.                   TempFontColor := caFontColor;
  1135.                 if (TempColor = clOvcTableDefault) then
  1136.                   if (RowNum < LockedRows) or (ColNum < LockedCols) then
  1137.                     TempColor := Colors.Locked
  1138.                   else
  1139.                     TempColor := caColor;
  1140.               end;
  1141.           end;
  1142.         caColor := TempColor;
  1143.         caFontColor := TempFontColor;
  1144.       end;
  1145.     DoGetCellAttributes(RowNum, ColNum, CellAttr);
  1146.   end;
  1147. {====================================================================}
  1148.  
  1149.  
  1150. {==TOvcTable property write routines=================================}
  1151. procedure TOvcCustomTable.SetAccess(A : TOvcTblAccess);
  1152.   var
  1153.     TempAccess : TOvcTblAccess;
  1154.   begin
  1155.     if (A = otxDefault) then
  1156.          TempAccess := tbDefAccess
  1157.     else TempAccess := A;
  1158.     if (TempAccess <> FAccess) then
  1159.       begin
  1160.         AllowRedraw := false;
  1161.         try
  1162.           if (TempAccess = otxInvisible) or (FAccess = otxInvisible) then
  1163.             InvalidateTable;
  1164.           FAccess := TempAccess;
  1165.         finally
  1166.           AllowRedraw := true;
  1167.         end;{try..finally}
  1168.       end;
  1169.   end;
  1170. {--------}
  1171. procedure TOvcCustomTable.SetActiveCell(RowNum : TRowNum; ColNum : TColNum);
  1172.   begin
  1173.     DoActiveCellMoving(ccNone, RowNum, ColNum);
  1174.     tbSetActiveCellWithSel(RowNum, ColNum);
  1175.   end;
  1176. {--------}
  1177. procedure TOvcCustomTable.tbSetActiveCellWithSel(RowNum : TRowNum;
  1178.                                                  ColNum : TColNum);
  1179.   begin
  1180.     if tbIsKeySelecting then
  1181.       tbUpdateSelection(RowNum, ColNum, tstDeselectAll)
  1182.     else
  1183.       tbSetAnchorCell(RowNum, ColNum, tstDeselectAll);
  1184.     tbSetActiveCellPrim(RowNum, ColNum);
  1185.   end;
  1186. {--------}
  1187. procedure TOvcCustomTable.tbSetActiveCellPrim(RowNum : TRowNum; ColNum : TColNum);
  1188.   var
  1189.     TempInvCells : TOvcCellArray;
  1190.   begin
  1191.     {verify the row/column numbers to be visible}
  1192.     RowNum := IncRow(RowNum, 0);
  1193.     ColNum := IncCol(ColNum, 0);
  1194.     {if nothing to do, get out}
  1195.     if (RowNum = FActiveRow) and (ColNum = FActiveCol) then
  1196.       Exit;
  1197.     {if can't do anything visually, just set the internal fields and
  1198.      then exit}
  1199.     if (not HandleAllocated) or
  1200.        (tbRowNums^.Count = 0) or (tbColNums^.Count = 0) then
  1201.       begin
  1202.         FActiveRow := RowNum;
  1203.         FActiveCol := ColNum;
  1204.         Exit;
  1205.       end;
  1206.     {set the new active cell}
  1207.     TempInvCells := nil;
  1208.     AllowRedraw := false;
  1209.     try
  1210.       TempInvCells := TOvcCellArray.Create;
  1211.       if (RowNum <> FActiveRow) then
  1212.         begin
  1213.           tbInvalidateRowHdgPrim(FActiveRow, TempInvCells);
  1214.           InvalidateRowHeading(RowNum);
  1215.           DoLeavingRow(FActiveRow);
  1216.         end;
  1217.       if (ColNum <> FActiveCol) then
  1218.         begin
  1219.           tbInvalidateColHdgPrim(FActiveCol, TempInvCells);
  1220.           InvalidateColumnHeading(ColNum);
  1221.           DoLeavingColumn(FActiveCol);
  1222.         end;
  1223.       tbInvCells.DeleteCell(ActiveRow, ActiveCol);
  1224.       TempInvCells.AddCell(ActiveRow, ActiveCol);
  1225.       FActiveRow := RowNum;
  1226.       FActiveCol := ColNum;
  1227.       tbDrawInvalidCells(TempInvCells);
  1228.       tbEnsureRowIsVisible(RowNum);
  1229.       tbEnsureColumnIsVisible(ColNum);
  1230.       if not (otsDesigning in tbState) and (otoAlwaysEditing in Options) then
  1231.         PostMessage(Handle, ctim_StartEdit, 0, 0)
  1232.       else
  1233.         InvalidateCell(ActiveRow, ActiveCol);
  1234.     finally
  1235.       AllowRedraw := true;
  1236.       TempInvCells.Free;
  1237.     end;{try..finally}
  1238.     tbSetScrollPos(otsbHorizontal);
  1239.     tbSetScrollPos(otsbVertical);
  1240.     DoActiveCellChanged(RowNum, ColNum);
  1241.   end;
  1242. {--------}
  1243. procedure TOvcCustomTable.SetActiveCol(ColNum : TColNum);
  1244.   begin
  1245.     SetActiveCell(FActiveRow, ColNum);
  1246.   end;
  1247. {--------}
  1248. procedure TOvcCustomTable.SetActiveRow(RowNum : TRowNum);
  1249.   begin
  1250.     SetActiveCell(RowNum, FActiveCol);
  1251.   end;
  1252. {--------}
  1253. procedure TOvcCustomTable.SetAdjust(A : TOvcTblAdjust);
  1254.   var
  1255.     TempAdjust : TOvcTblAdjust;
  1256.   begin
  1257.     if (A = otaDefault) then
  1258.          TempAdjust := tbDefAdjust
  1259.     else TempAdjust := A;
  1260.     if (TempAdjust <> FAdjust) then
  1261.       begin
  1262.         AllowRedraw := false;
  1263.         try
  1264.           InvalidateTable;
  1265.           FAdjust := TempAdjust;
  1266.         finally
  1267.           AllowRedraw := true;
  1268.         end;{try..finally}
  1269.       end;
  1270.   end;
  1271. {--------}
  1272. procedure TOvcCustomTable.SetAllowRedraw(AR : boolean);
  1273.   var
  1274.     CellRect : TRect;
  1275.     MustFocus: boolean;
  1276.     R        : TRect;
  1277.     CellStyle: TOvcTblEditorStyle;
  1278.   begin
  1279.     if AR {AllowRedraw is true} then
  1280.       begin
  1281.         dec(tbLockCount);
  1282.         if (tbLockCount <= 0) then
  1283.           begin
  1284.             {Setting the tbLockCount explicitly to zero is to catch
  1285.              programmers who call AllowRedraw := true once to often}
  1286.             tbLockCount := 0;
  1287.             {Update the scroll bars}
  1288.             if tbUpdateSBs then
  1289.               begin
  1290.                 tbUpdateSBs := false;
  1291.                 tbSetScrollPos(otsbHorizontal);
  1292.                 tbSetScrollPos(otsbVertical);
  1293.               end;
  1294.             {if in row selection mode invalidate it}
  1295.             if (otoBrowseRow in Options) then
  1296.               InvalidateRow(ActiveRow);
  1297.             {draw the invalid and active cells if we have a handle}
  1298.             if HandleAllocated then
  1299.               begin
  1300.                 {redraw invalid cells}
  1301.                 if not tbInvCells.Empty then
  1302.                   tbDrawInvalidCells(tbInvCells);
  1303.                 if (otsHiddenEdit in tbState) then
  1304.                   begin
  1305.                     if tbCalcActiveCellRect(CellRect) then
  1306.                       begin
  1307.                         {note: cell style is ignored here}
  1308.                         CellStyle := tesNormal;
  1309.                         DoSizeCellEditor(ActiveRow, ActiveCol, CellRect, CellStyle);
  1310.                         MustFocus := Focused;
  1311.                         tbActCell.EditMove(CellRect);
  1312.                         tbState := tbState - [otsHiddenEdit] + [otsEditing];
  1313.                         if MustFocus then
  1314.                           {$IFDEF Win32}
  1315.                           Windows.SetFocus(tbActCell.EditHandle);
  1316.                           {$ELSE}
  1317.                           WinProcs.SetFocus(tbActCell.EditHandle);
  1318.                           {$ENDIF}
  1319.                       end
  1320.                   end
  1321.                 else
  1322.                   tbDrawActiveCell;
  1323.               end;
  1324.           end;
  1325.       end
  1326.     else
  1327.       begin
  1328.         inc(tbLockCount);
  1329.         if (tbLockCount = 1) and (HandleAllocated) then
  1330.           begin
  1331.             if (otoBrowseRow in Options) then
  1332.               InvalidateRow(ActiveRow);
  1333.             if (otsEditing in tbState) then
  1334.               begin
  1335.                 {$IFDEF Win32}
  1336.                 MustFocus := tbEditCellHasFocus(Windows.GetFocus);
  1337.                 {$ELSE}
  1338.                 MustFocus := tbEditCellHasFocus(WinProcs.GetFocus);
  1339.                 {$ENDIF}
  1340.                 GetWindowRect(tbActCell.EditHandle, R);
  1341.                 R.TopLeft := ScreenToClient(R.TopLeft);
  1342.                 R.BottomRight := ScreenToClient(R.BottomRight);
  1343.                 InvalidateCellsInRect(R);
  1344.                 tbActCell.EditHide;
  1345.                 tbState := tbState - [otsEditing] + [otsHiddenEdit];
  1346.                 if MustFocus then
  1347.                   SetFocus;
  1348.               end
  1349.             else if not (otoBrowseRow in Options) then
  1350.               InvalidateCell(ActiveRow, ActiveCol);
  1351.           end;
  1352.       end;
  1353.   end;
  1354. {--------}
  1355. procedure TOvcCustomTable.SetBorderStyle(const BS : TBorderStyle);
  1356.   begin
  1357.     if (BS <> BorderStyle) then
  1358.       begin
  1359.         FBorderStyle := BS;
  1360.         RecreateWnd;
  1361.       end;
  1362.   end;
  1363. {--------}
  1364. procedure TOvcCustomTable.SetBlockAccess(A : TOvcTblAccess);
  1365.   var
  1366.     R : TRowNum;
  1367.     C : TColNum;
  1368.   begin
  1369.     for R := BlockRowBegin to BlockRowEnd do
  1370.       for C := BlockColBegin to BlockColEnd do
  1371.         FCells.Access[R, C] := A;
  1372.   end;
  1373. {--------}
  1374. procedure TOvcCustomTable.SetBlockAdjust(A : TOvcTblAdjust);
  1375.   var
  1376.     R : TRowNum;
  1377.     C : TColNum;
  1378.   begin
  1379.     for R := BlockRowBegin to BlockRowEnd do
  1380.       for C := BlockColBegin to BlockColEnd do
  1381.         FCells.Adjust[R, C] := A;
  1382.   end;
  1383. {--------}
  1384. procedure TOvcCustomTable.SetBlockCell(C : TOvcBaseTableCell);
  1385.   var
  1386.     Rn : TRowNum;
  1387.     Cn : TColNum;
  1388.   begin
  1389.     for Rn := BlockRowBegin to BlockRowEnd do
  1390.       for Cn := BlockColBegin to BlockColEnd do
  1391.         FCells.Cell[Rn, Cn] := C;
  1392.   end;
  1393. {--------}
  1394. procedure TOvcCustomTable.SetBlockColBegin(ColNum : TColNum);
  1395.   begin
  1396.     if (ColNum <> FBlockColBegin) then
  1397.       if (0 <= ColNum) and (ColNum < ColCount) then
  1398.         begin
  1399.           FBlockColBegin := ColNum;
  1400.           if (FBlockColEnd < FBlockColBegin) then
  1401.             FBlockColEnd := ColNum;
  1402.         end;
  1403.   end;
  1404. {--------}
  1405. procedure TOvcCustomTable.SetBlockColEnd(ColNum : TColNum);
  1406.   begin
  1407.     if (ColNum <> FBlockColEnd) then
  1408.       if (0 <= ColNum) and (ColNum < ColCount) then
  1409.         begin
  1410.           FBlockColEnd := ColNum;
  1411.           if (FBlockColEnd < FBlockColBegin) then
  1412.             FBlockColBegin := ColNum;
  1413.         end;
  1414.   end;
  1415. {--------}
  1416. procedure TOvcCustomTable.SetBlockColor(C : TColor);
  1417.   var
  1418.     Rn : TRowNum;
  1419.     Cn : TColNum;
  1420.   begin
  1421.     for Rn := BlockRowBegin to BlockRowEnd do
  1422.       for Cn := BlockColBegin to BlockColEnd do
  1423.         FCells.Color[Rn, Cn] := C;
  1424.   end;
  1425. {--------}
  1426. procedure TOvcCustomTable.SetBlockFont(F : TFont);
  1427.   var
  1428.     R : TRowNum;
  1429.     C : TColNum;
  1430.   begin
  1431.     for R := BlockRowBegin to BlockRowEnd do
  1432.       for C := BlockColBegin to BlockColEnd do
  1433.         FCells.Font[R, C] := F;
  1434.   end;
  1435. {--------}
  1436. procedure TOvcCustomTable.SetBlockRowBegin(RowNum : TRowNum);
  1437.   begin
  1438.     if (RowNum <> FBlockRowBegin) then
  1439.       if (0 <= RowNum) and (RowNum < RowLimit) then
  1440.         begin
  1441.           FBlockRowBegin := RowNum;
  1442.           if (FBlockRowEnd < FBlockRowBegin) then
  1443.             FBlockRowEnd    := RowNum;
  1444.         end;
  1445.   end;
  1446. {--------}
  1447. procedure TOvcCustomTable.SetBlockRowEnd(RowNum : TRowNum);
  1448.   begin
  1449.     if (RowNum <> FBlockRowEnd) then
  1450.       if (0 <= RowNum) and (RowNum < RowLimit) then
  1451.         begin
  1452.           FBlockRowEnd := RowNum;
  1453.           if (FBlockRowEnd < FBlockRowBegin) then
  1454.             FBlockRowBegin := RowNum;
  1455.         end;
  1456.   end;
  1457. {--------}
  1458. procedure TOvcCustomTable.SetColors(C : TOvcTableColors);
  1459.   begin
  1460.     FColors.Assign(C);
  1461.   end;
  1462. {--------}
  1463. procedure TOvcCustomTable.SetColorUnused(CU : TColor);
  1464.   begin
  1465.     if (CU <> ColorUnused) then
  1466.       begin
  1467.         AllowRedraw := false;
  1468.         FColorUnused := CU;
  1469.         tbInvCells.AddUnusedBit;
  1470.         AllowRedraw := true;
  1471.       end;
  1472.   end;
  1473. {--------}
  1474. procedure TOvcCustomTable.SetColCount(CC : integer);
  1475.   begin
  1476.     if (CC <> ColCount) and (CC > LockedCols) then
  1477.       begin
  1478.         AllowRedraw := false;
  1479.         try
  1480.           Columns.Count := CC;
  1481.           tbSelList.SetColCount(CC);
  1482.           tbSetScrollRange(otsbHorizontal);
  1483.           if (CC <= ActiveCol) then
  1484.             ActiveCol := pred(CC);
  1485.           if (CC <= LeftCol) then
  1486.             LeftCol := pred(CC);
  1487.           if (CC <= FSelAnchorCol) then
  1488.             FSelAnchorCol := pred(CC);
  1489.           if (CC <= BlockColBegin) then
  1490.             BlockColBegin := pred(CC);
  1491.           if (CC <= BlockColEnd) then
  1492.             BlockColEnd := pred(CC);
  1493.           tbSetScrollPos(otsbHorizontal);
  1494.         finally
  1495.           AllowRedraw := true;
  1496.         end;{try..finally}
  1497.       end;
  1498.   end;
  1499. {--------}
  1500. procedure TOvcCustomTable.SetCols(CS : TOvcTableColumns);
  1501.   begin
  1502.     AllowRedraw := false;
  1503.     try
  1504.       FCols.Free;
  1505.       FCols := CS;
  1506.       FCols.Table := Self;
  1507.       FCols.OnColumnChanged := tbColChanged;
  1508.       tbColChanged(FCols, 0, 0, taGeneral);
  1509.     finally
  1510.       AllowRedraw := true;
  1511.     end;{try..finally}
  1512.   end;
  1513. {--------}
  1514. procedure TOvcCustomTable.SetLeftCol(ColNum : TColNum);
  1515.   begin
  1516.     SetTopLeftCell(TopRow, ColNum);
  1517.   end;
  1518. {--------}
  1519. procedure TOvcCustomTable.SetLockedCols(ColNum : TColNum);
  1520.   begin
  1521.     if not HandleAllocated then
  1522.       FLockedCols := ColNum
  1523.     else
  1524.       if (ColNum <> FLockedCols) then
  1525.         if (0 <= ColNum) and (ColNum < ColCount) then
  1526.           begin
  1527.             AllowRedraw := false;
  1528.             try
  1529.               FLockedCols := ColNum;
  1530.               if LeftCol < ColNum then
  1531.                 LeftCol := LeftCol; {this does do something!}
  1532.               if (ActiveCol < ColNum) then
  1533.                 ActiveCol := LeftCol; {this does do something!}
  1534.               tbCalcColData(tbColNums, LeftCol);
  1535.               InvalidateTable;
  1536.             finally
  1537.               AllowRedraw := true;
  1538.             end;{try..finally}
  1539.             tbSetScrollRange(otsbHorizontal);
  1540.             tbSetScrollPos(otsbHorizontal);
  1541.           end;
  1542.   end;
  1543. {--------}
  1544. procedure TOvcCustomTable.SetLockedRows(RowNum : TRowNum);
  1545.   begin
  1546.     if not HandleAllocated then
  1547.       FLockedRows := RowNum
  1548.     else
  1549.       if (RowNum <> FLockedRows) then
  1550.         if (0 <= RowNum) then
  1551.           begin
  1552.             AllowRedraw := false;
  1553.             try
  1554.               FLockedRows := RowNum;
  1555.               if (TopRow < RowNum) then
  1556.                 TopRow := TopRow; {this does do something!}
  1557.               if (ActiveRow < RowNum) then
  1558.                 ActiveRow := ActiveRow; {this does do something!}
  1559.               tbCalcRowData(tbRowNums, TopRow);
  1560.               InvalidateTable;
  1561.             finally
  1562.               AllowRedraw := true;
  1563.             end;{try..finally}
  1564.             tbSetScrollRange(otsbVertical);
  1565.             tbSetScrollPos(otsbVertical);
  1566.           end;
  1567.   end;
  1568. {--------}
  1569. procedure TOvcCustomTable.SetLockedRowsCell(C : TOvcBaseTableCell);
  1570.   var
  1571.     DoIt : boolean;
  1572.   begin
  1573.     DoIt := false;
  1574.     if (C <> FLockedRowsCell) then
  1575.       if Assigned(C) then
  1576.         begin
  1577.           if (C.References = 0) or
  1578.              ((C.References > 0) and (C.Table = Self)) then
  1579.             DoIt := true;
  1580.         end
  1581.       else
  1582.         DoIt := true;
  1583.  
  1584.     if DoIt then
  1585.       begin
  1586.         if Assigned(FLockedRowsCell) then
  1587.           FLockedRowsCell.DecRefs;
  1588.         FLockedRowsCell := C;
  1589.         if Assigned(FLockedRowsCell) then
  1590.           begin
  1591.             if (FLockedRowsCell.References = 0) then
  1592.               FLockedRowsCell.Table := Self;
  1593.             FLockedRowsCell.IncRefs;
  1594.           end;
  1595.         tbCellChanged(Self);
  1596.       end;
  1597.   end;
  1598. {--------}
  1599. procedure TOvcCustomTable.SetOptions(O : TOvcTblOptionSet);
  1600.   begin
  1601.     AllowRedraw := false;
  1602.     try
  1603.       FOptions := O;
  1604.       if HaveSelection then
  1605.         begin
  1606.           tbIsSelecting := false;
  1607.           tbIsDeselecting := false;
  1608.           tbSetAnchorCell(ActiveRow, ActiveCol, tstDeselectAll);
  1609.         end;
  1610.       {patch up the options set to exclude meaningless combinations}
  1611.       if (otoBrowseRow in FOptions) then
  1612.         begin
  1613.           FOptions := FOptions +
  1614.              [otoNoSelection, otoNoRowResizing, otoNoColResizing] -
  1615.              [otoMouseDragSelect, otoRowSelection, otoColSelection];
  1616.         end;
  1617.       if (otoAlwaysEditing in FOptions) then
  1618.         begin
  1619.           FOptions := FOptions +
  1620.              [otoNoSelection, otoNoRowResizing, otoNoColResizing] -
  1621.              [otoMouseDragSelect, otoRowSelection, otoColSelection];
  1622.         end
  1623.       else if (otoNoSelection in FOptions) then
  1624.         begin
  1625.           FOptions := FOptions -
  1626.              [otoMouseDragSelect, otoRowSelection, otoColSelection];
  1627.         end;
  1628.       if (otoRowSelection in FOptions) then
  1629.         FOptions := FOptions - [otoAllowRowMoves];
  1630.       if (otoColSelection in FOptions) then
  1631.         FOptions := FOptions - [otoAllowColMoves];
  1632.       InvalidateTable;
  1633.     finally
  1634.       AllowRedraw := true;
  1635.     end;{try..finally}
  1636.   end;
  1637. {--------}
  1638. procedure TOvcCustomTable.SetPaintUnusedArea(PUA : TNotifyEvent);
  1639.   begin
  1640.     AllowRedraw := false;
  1641.     FPaintUnusedArea := PUA;
  1642.     tbInvCells.AddUnusedBit;
  1643.     AllowRedraw := true;
  1644.   end;
  1645. {--------}
  1646. procedure TOvcCustomTable.SetRowLimit(RowNum : TRowNum);
  1647.   begin
  1648.     if (RowNum <> FRows.Limit) and (RowNum > LockedRows) then
  1649.       begin
  1650.         AllowRedraw := false;
  1651.         try
  1652.           FRows.Limit := RowNum;
  1653.           tbSelList.SetRowCount(RowLimit);
  1654.           tbSetScrollRange(otsbVertical);
  1655.           if (RowNum <= ActiveRow) then
  1656.             ActiveRow := pred(RowNum);
  1657.           if (RowNum <= TopRow) then
  1658.             TopRow := pred(RowNum);
  1659.           if (RowNum <= FSelAnchorRow) then
  1660.             FSelAnchorRow := pred(RowNum);
  1661.           if (RowNum <= BlockRowBegin) then
  1662.             BlockRowBegin := pred(RowNum);
  1663.           if (RowNum <= BlockRowEnd) then
  1664.             BlockRowEnd := pred(RowNum);
  1665.           tbSetScrollPos(otsbVertical);
  1666.         finally
  1667.           AllowRedraw := true;
  1668.         end;{try..finally}
  1669.       end;
  1670.   end;
  1671. {--------}
  1672. procedure TOvcCustomTable.SetRows(RS : TOvcTableRows);
  1673.   begin
  1674.     AllowRedraw := false;
  1675.     try
  1676.       FRows.Free;
  1677.       FRows := RS;
  1678.     finally
  1679.       AllowRedraw := true;
  1680.     end;{try..finally}
  1681.   end;
  1682. {--------}
  1683. procedure TOvcCustomTable.SetScrollBars(const SB : TScrollStyle);
  1684.   begin
  1685.     if (SB <> ScrollBars) then
  1686.       begin
  1687.         FScrollBars := SB;
  1688.         RecreateWnd;
  1689.       end;
  1690.   end;
  1691. {--------}
  1692. procedure TOvcCustomTable.SetTopRow(RowNum : TRowNum);
  1693.   begin
  1694.     SetTopLeftCell(RowNum, LeftCol);
  1695.   end;
  1696. {--------}
  1697. procedure TOvcCustomTable.SetTopLeftCell(RowNum : TRowNum; ColNum : TColNum);
  1698.   begin
  1699.     {ensure that the new top left cell minimises the unused space}
  1700.     if (ColNum > tbLastLeftCol) then
  1701.       ColNum := tbLastLeftCol;
  1702.     if (RowNum > tbLastTopRow) then
  1703.       RowNum := tbLastTopRow;
  1704.     {ensure that RowNum and C are not hidden}
  1705.     RowNum := IncRow(RowNum, 0);
  1706.     ColNum := IncCol(ColNum, 0);
  1707.     DoTopLeftCellChanging(RowNum, ColNum);
  1708.     {change the topmost row and leftmost column if required}
  1709.     if not HandleAllocated then
  1710.       begin
  1711.         FTopRow := RowNum;
  1712.         FLeftCol := ColNum;
  1713.       end
  1714.     else
  1715.       if (RowNum <> FTopRow) or (ColNum <> FLeftCol) then
  1716.         begin
  1717.           AllowRedraw := false;
  1718.           {note: the tbScrollTableXxx routines set FTopRow and FLeftCol}
  1719.           try
  1720.             if (RowNum > FTopRow) then
  1721.               tbScrollTableUp(RowNum)
  1722.             else if (RowNum < FTopRow) then
  1723.               tbScrollTableDown(RowNum);
  1724.             if (ColNum > FLeftCol) then
  1725.               tbScrollTableLeft(ColNum)
  1726.             else if (ColNum < FLeftCol) then
  1727.               tbScrollTableRight(ColNum);
  1728.           finally
  1729.             AllowRedraw := true;
  1730.           end;{try..finally}
  1731.           tbSetScrollPos(otsbVertical);
  1732.           tbSetScrollPos(otsbHorizontal);
  1733.           DoTopLeftCellChanged(RowNum, ColNum);
  1734.         end;
  1735.   end;
  1736. {====================================================================}
  1737.  
  1738.  
  1739. {==TOvcTable Scroller routines=======================================}
  1740. procedure TOvcCustomTable.tbSetScrollPos(SB : TOvcScrollBar);
  1741.   var
  1742.     ColNum  : TColNum;
  1743.     ColCnt  : TColNum;
  1744.     Divisor : LongInt;
  1745.   begin
  1746.     if (SB = otsbVertical) then
  1747.       begin
  1748.         if tbHasVSBar then
  1749.           if HandleAllocated and (tbLockCount = 0) then
  1750.             begin
  1751.               if (tbLastTopRow < 16*1024) then
  1752.                 SetScrollPos(Handle, SB_VERT, TopRow, true)
  1753.               else
  1754.                 begin
  1755.                   Divisor := RowLimit div $400;
  1756.                   SetScrollPos(Handle, SB_VERT,
  1757.                                         TopRow div Divisor,
  1758.                                         True);
  1759.                 end
  1760.             end
  1761.           else
  1762.             tbUpdateSBs := true;
  1763.       end
  1764.     else {SB = otsbHorizontal}
  1765.       begin
  1766.         if tbHasHSBar then
  1767.           if HandleAllocated and (tbLockCount = 0) then
  1768.             begin
  1769.               ColCnt := 0;
  1770.               for ColNum := LockedCols to pred(LeftCol) do
  1771.                 if not tbIsColHidden(ColNum) then
  1772.                   inc(ColCnt);
  1773.               SetScrollPos(Handle, SB_HORZ, ColCnt, true)
  1774.             end
  1775.           else
  1776.             tbUpdateSBs := true;
  1777.       end;
  1778.   end;
  1779. {--------}
  1780. procedure TOvcCustomTable.tbSetScrollRange(SB : TOvcScrollBar);
  1781.   var
  1782.     Divisor : LongInt;
  1783.   begin
  1784.     if (SB = otsbVertical) then
  1785.       begin
  1786.         if tbHasVSBar and HandleAllocated then
  1787.           begin
  1788.             tbCalcRowsOnLastPage;
  1789.             if (tbLastTopRow < 16*1024) then
  1790.               if tbCalcRequiresVSBar then
  1791.                 SetScrollRange(Handle, SB_Vert, LockedRows, tbLastTopRow, false)
  1792.               else
  1793.                 SetScrollRange(Handle, SB_Vert, LockedRows, LockedRows, false)
  1794.             else
  1795.               begin
  1796.                 Divisor := Succ(tbLastTopRow div $400);
  1797.                 SetScrollRange(Handle, SB_Vert,
  1798.                                         LockedRows, tbLastTopRow div Divisor,
  1799.                                         False)
  1800.               end;
  1801.           end
  1802.       end
  1803.     else {SB = otsbHorizontal}
  1804.       begin
  1805.         tbCalcColsOnLastPage;
  1806.         if tbHasHSBar and HandleAllocated then
  1807.           begin
  1808.             tbCalcHSBarPosCount;
  1809.             SetScrollRange(Handle, SB_HORZ, 0, pred(tbHSBarPosCount), false);
  1810.           end;
  1811.       end;
  1812.   end;
  1813. {====================================================================}
  1814.  
  1815.  
  1816. {==TOvcTable editing routines========================================}
  1817. function TOvcCustomTable.FilterKey(var Msg : TWMKey) : TOvcTblKeyNeeds;
  1818.   var
  1819.     Cmd : word;
  1820.   begin
  1821.     Result := otkDontCare;
  1822.     Cmd := Controller.EntryCommands.TranslateUsing([tbCmdTable^], TMessage(Msg));
  1823.     {first the hard coded keys}
  1824.     case Msg.CharCode of
  1825.       VK_RETURN :
  1826.         if (otoEnterToArrow in Options) then
  1827.           Result := otkMustHave;
  1828.       VK_TAB :
  1829.         if (otoTabToArrow in Options) then
  1830.           Result := otkMustHave;
  1831.       VK_ESCAPE :
  1832.        Result := otkMustHave;
  1833.     end;{case}
  1834.     {now the translated commands}
  1835.     case Cmd of
  1836.       ccTableEdit :
  1837.         Result := otkMustHave;
  1838.       ccBotOfPage, ccBotRightCell, ccDown, ccEnd, ccFirstPage, ccHome,
  1839.       ccLastPage, ccLeft, ccNextPage, ccPageLeft, ccPageRight, ccPrevPage,
  1840.       ccRight, ccTopLeftCell, ccTopOfPage, ccUp, ccWordLeft, ccWordRight :
  1841.         Result := otkWouldLike;
  1842.     end;{case}
  1843.   end;
  1844. {--------}
  1845. function TOvcCustomTable.SaveEditedData : boolean;
  1846.   var
  1847.     Data      : pointer;
  1848.   begin
  1849.     Result := true;
  1850.     if InEditingState then
  1851.       begin
  1852.         Result := false;
  1853.         if not tbActCell.CanSaveEditedData(true) then
  1854.           Exit;
  1855.         Result := true;
  1856.         DoEnteringColumn(ActiveCol);
  1857.         DoEnteringRow(ActiveRow);
  1858.         DoGetCellData(ActiveRow, ActiveCol, Data, cdpForSave);
  1859.         tbActCell.SaveEditedData(Data);
  1860.       end;
  1861.   end;
  1862. {--------}
  1863. function TOvcCustomTable.StartEditingState : boolean;
  1864.   var
  1865.     CellRect : TRect;
  1866.     Data     : pointer;
  1867.     CellAttr : TOvcCellAttributes;
  1868.     CellStyle: TOvcTblEditorStyle;
  1869.   begin
  1870.     Result := true;
  1871.     if InEditingState then
  1872.       Exit;
  1873.     DoBeginEdit(ActiveRow, ActiveCol, Result);
  1874.     if not Result then
  1875.       Exit;
  1876.     Result := false;
  1877.     AllowRedraw := false;
  1878.     try
  1879.       tbEnsureRowIsVisible(ActiveRow);
  1880.       tbEnsureColumnIsVisible(ActiveCol);
  1881.       tbActCell := tbFindCell(ActiveRow, ActiveCol);
  1882.       if Assigned(tbActCell) then
  1883.         begin
  1884.           FillChar(CellAttr, sizeof(CellAttr), 0);
  1885.           CellAttr.caFont := tbCellAttrFont;
  1886.           CellAttr.caFont.Assign(Font);
  1887.           tbActCell.ResolveAttributes(ActiveRow, ActiveCol, CellAttr);
  1888.           if (CellAttr.caAccess = otxNormal) then
  1889.             begin
  1890.               if not tbCalcActiveCellRect(CellRect) then
  1891.                 {we're in big trouble, lads};
  1892.               CellStyle := tesNormal;
  1893.               DoSizeCellEditor(ActiveRow, ActiveCol, CellRect, CellStyle);
  1894.               DoEnteringColumn(ActiveCol);
  1895.               DoEnteringRow(ActiveRow);
  1896.               DoGetCellData(ActiveRow, ActiveCol, Data, cdpForEdit);
  1897.               tbState := tbState - [otsNormal] + [otsHiddenEdit];
  1898.               CellAttr.caColor := Colors.Editing;
  1899.               CellAttr.caFontColor := Colors.EditingText;
  1900.               tbActCell.StartEditing(ActiveRow, ActiveCol, CellRect, CellAttr, CellStyle, Data);
  1901.               Result := (tbActCell.EditHandle <> 0);
  1902.               if not Result then
  1903.                 begin
  1904.                   tbState := tbState + [otsNormal] - [otsHiddenEdit];
  1905.                   tbActCell := nil;
  1906.                 end;
  1907.             end
  1908.           else
  1909.             tbActCell := nil;
  1910.         end;
  1911.     finally
  1912.       AllowRedraw := true;
  1913.     end;{try..finally}
  1914.   end;
  1915. {--------}
  1916. function TOvcCustomTable.StopEditingState(SaveValue : boolean) : boolean;
  1917.   var
  1918.     Data      : pointer;
  1919.     MustFocus : boolean;
  1920.  
  1921.     R : TRect;
  1922.  
  1923.   begin
  1924.     Result := true;
  1925.     if not InEditingState then
  1926.       Exit;
  1927.     Result := false;
  1928.     if not tbActCell.CanSaveEditedData(SaveValue) then
  1929.       Exit;
  1930.     DoEndEdit(tbActCell, ActiveRow, ActiveCol, Result);
  1931.     if not Result then
  1932.       Exit;
  1933.     Result := true;
  1934.     GetWindowRect(tbActCell.EditHandle, R);
  1935.     AllowRedraw := false;
  1936.     try
  1937.       {$IFDEF Win32}
  1938.       MustFocus := tbEditCellHasFocus(Windows.GetFocus);
  1939.       {$ELSE}
  1940.       MustFocus := tbEditCellHasFocus(WinProcs.GetFocus);
  1941.       {$ENDIF}
  1942.       if not MustFocus then
  1943.         MustFocus := Focused;
  1944.       DoEnteringColumn(ActiveCol);
  1945.       DoEnteringRow(ActiveRow);
  1946.       DoGetCellData(ActiveRow, ActiveCol, Data, cdpForSave);
  1947.  
  1948.       R.TopLeft := ScreenToClient(R.TopLeft);
  1949.       R.BottomRight := ScreenToClient(R.BottomRight);
  1950.       InvalidateCellsInRect(R);
  1951.  
  1952.       tbActCell.StopEditing(SaveValue, Data);
  1953.       tbActCell := nil;
  1954.       try
  1955.         DoDoneEdit(ActiveRow, ActiveCol);
  1956.       finally
  1957.         if not (otoAlwaysEditing in Options) then
  1958.           InvalidateCell(ActiveRow, ActiveCol);
  1959.         tbState := tbState - [otsEditing, otsHiddenEdit] + [otsNormal];
  1960.         if MustFocus then
  1961.           SetFocus
  1962.         else
  1963.           tbState := tbState - [otsFocused] + [otsUnfocused];
  1964.       end;{try..finally}
  1965.     finally
  1966.       AllowRedraw := true;
  1967.     end;{try..finally}
  1968.   end;
  1969. {====================================================================}
  1970.  
  1971.  
  1972. {==TOvcTable selection methods=======================================}
  1973. procedure TOvcCustomTable.tbDeselectAll(CA : TOvcCellArray);
  1974.   begin
  1975.     with tbSelList do
  1976.       begin
  1977.         Iterate(tbDeselectAllIterator, pointer(CA));
  1978.         DeselectAll;
  1979.       end;
  1980.   end;
  1981. {--------}
  1982. function TOvcCustomTable.tbDeselectAllIterator(RowNum1 : TRowNum; ColNum1 : TColNum;
  1983.                                                RowNum2 : TRowNum; ColNum2 : TColNum;
  1984.                                                ExtraData : pointer) : boolean;
  1985.   var
  1986.     RowNum : TRowNum;
  1987.     ColNum : TColNum;
  1988.     RowInx : integer;
  1989.     CA : TOvcCellArray absolute ExtraData;
  1990.   begin
  1991.     {optimisations: 1. generally ColNum1 = ColNum2
  1992.                     2. take it from the viewpoint of what rows are visible
  1993.                        rather than what rows are selected}
  1994.     Result := true;
  1995.     for ColNum := ColNum1 to ColNum2 do
  1996.       if (tbFindColInx(ColNum) <> -1) then
  1997.         with tbRowNums^ do
  1998.           for RowInx := 0 to pred(Count) do
  1999.             begin
  2000.               RowNum := Ay[RowInx].Number;
  2001.               if (RowNum1 <= RowNum) and (RowNum <= RowNum2) then
  2002.                 CA.AddCell(RowNum, ColNum);
  2003.             end;
  2004.   end;
  2005. {--------}
  2006. function TOvcCustomTable.HaveSelection : boolean;
  2007.   begin
  2008.     Result := tbSelList.HaveSelection;
  2009.   end;
  2010. {--------}
  2011. function TOvcCustomTable.InSelection(RowNum : TRowNum; ColNum : TColNum) : boolean;
  2012.   begin
  2013.     if HaveSelection then
  2014.       Result := tbSelList.IsCellSelected(RowNum, ColNum)
  2015.     else
  2016.       Result := false;
  2017.   end;
  2018. {--------}
  2019. procedure TOvcCustomTable.IterateSelections(SI : TSelectionIterator; ExtraData : pointer);
  2020.   begin
  2021.     with tbSelList do
  2022.       Iterate(SI, ExtraData);
  2023.   end;
  2024. {--------}
  2025. procedure TOvcCustomTable.tbSelectCol(ColNum : TColNum);
  2026.   var
  2027.     RowInx : integer;
  2028.     ColInx : integer;
  2029.   begin
  2030.     tbSelList.SelectCellRange(LockedRows, ColNum, pred(RowLimit), ColNum);
  2031.     ColInx := tbFindColInx(ColNum);
  2032.     if (ColInx <> -1) then
  2033.       with tbRowNums^ do
  2034.         for RowInx := 0 to pred(Count) do
  2035.           tbInvCells.AddCell(Ay[RowInx].Number, ColNum);
  2036.   end;
  2037. {--------}
  2038. procedure TOvcCustomTable.tbSelectRow(RowNum : TRowNum);
  2039.   var
  2040.     RowInx : integer;
  2041.     ColInx : integer;
  2042.   begin
  2043.     tbSelList.SelectCellRange(RowNum, LockedCols, RowNum, pred(ColCount));
  2044.     RowInx := tbFindRowInx(RowNum);
  2045.     if (RowInx <> -1) then
  2046.       with tbColNums^ do
  2047.         for ColInx := 0 to pred(Count) do
  2048.           tbInvCells.AddCell(RowNum, Ay[ColInx].Number);
  2049.   end;
  2050. {--------}
  2051. procedure TOvcCustomTable.tbSelectTable;
  2052.   begin
  2053.     tbSelList.SelectAll;
  2054.     InvalidateTable;
  2055.   end;
  2056. {--------}
  2057. procedure TOvcCustomTable.tbSetAnchorCell(RowNum : TRowNum; ColNum : TColNum;
  2058.                                           Action : TOvcTblSelectionType);
  2059.   begin
  2060.     {deselect the current selection(s) if required}
  2061.     if (Action = tstDeselectAll) then
  2062.       tbDeselectAll(tbInvCells);
  2063.     {set the anchor point to a sensible value}
  2064.     if (ColNum < LockedCols) then
  2065.       FSelAnchorCol := LockedCols
  2066.     else if (ColNum >= ColCount) then
  2067.       FSelAnchorCol := pred(ColCount)
  2068.     else
  2069.       FSelAnchorCol := ColNum;
  2070.     if (RowNum < LockedRows) then
  2071.       FSelAnchorRow := LockedRows
  2072.     else if (RowNum >= RowLimit) then
  2073.       FSelAnchorRow := pred(RowLimit)
  2074.     else
  2075.       FSelAnchorRow := RowNum;
  2076.     {tell the selection list object}
  2077.     tbSelList.SetRangeAnchor(RowNum, ColNum, Action);
  2078.     {try and work out whether we are selecting or deselecting}
  2079.     tbIsSelecting := false;
  2080.     tbIsDeselecting := false;
  2081.     if (Action = tstAdditional) then
  2082.       begin
  2083.         if InSelection(RowNum, ColNum) then
  2084.           tbIsDeselecting := true
  2085.         else
  2086.           tbIsSelecting := true;
  2087.       end;
  2088.   end;
  2089. {--------}
  2090. procedure TOvcCustomTable.tbUpdateSelection(RowNum : TRowNum; ColNum : TColNum;
  2091.                                             Action : TOvcTblSelectionType);
  2092.   var
  2093.     R          : TRowNum;
  2094.     C          : TColNum;
  2095.     OldSelRow1 : TRowNum;
  2096.     OldSelRow2 : TRowNum;
  2097.     OldSelCol1 : TColNum;
  2098.     OldSelCol2 : TColNum;
  2099.     NewSelRow1 : TRowNum;
  2100.     NewSelRow2 : TRowNum;
  2101.     NewSelCol1 : TColNum;
  2102.     NewSelCol2 : TColNum;
  2103.     RowInx     : integer;
  2104.     ColInx     : integer;
  2105.     NewInvCells: TOvcCellArray;
  2106.     DeselCells : TOvcCellArray;
  2107.   begin
  2108.     NewInvCells := nil;
  2109.     DeselCells := nil;
  2110.     try
  2111.       {create temporary cell arrays: one for new invalid cells,
  2112.        one for any deselected cells}
  2113.       NewInvCells := TOvcCellArray.Create;
  2114.       DeselCells := TOvcCellArray.Create;
  2115.       {deselect currently selected cells if required}
  2116.       if (Action = tstDeselectAll) then
  2117.         tbDeselectAll(DeselCells);
  2118.       {calculate the old and new selections (the parameters RowNum,
  2119.        ColNum form the address of the new active cell)}
  2120.       OldSelRow1 := MinL(ActiveRow, FSelAnchorRow);
  2121.       OldSelRow2 := MaxL(ActiveRow, FSelAnchorRow);
  2122.       NewSelRow1 := MinL(RowNum, FSelAnchorRow);
  2123.       NewSelRow2 := MaxL(RowNum, FSelAnchorRow);
  2124.       if (otoBrowseRow in Options) then
  2125.         begin
  2126.           OldSelCol1 := LockedCols;
  2127.           OldSelCol2 := pred(ColCount);
  2128.           NewSelCol1 := LockedCols;
  2129.           NewSelCol2 := pred(ColCount);
  2130.         end
  2131.       else
  2132.         begin
  2133.           OldSelCol1 := MinI(ActiveCol, FSelAnchorCol);
  2134.           OldSelCol2 := MaxI(ActiveCol, FSelAnchorCol);
  2135.           NewSelCol1 := MinI(ColNum, FSelAnchorCol);
  2136.           NewSelCol2 := MaxI(ColNum, FSelAnchorCol);
  2137.         end;
  2138.       {extend the range in the selection list}
  2139.       tbSelList.ExtendRange(RowNum, ColNum, tbIsSelecting or tbIsKeySelecting);
  2140.       {for the old selection, remove the cells from the deselected cell
  2141.        array (if they are there) and add them to the new selected cell
  2142.        array}
  2143.       for RowInx := 0 to pred(tbRowNums^.Count) do
  2144.         begin
  2145.           R := tbRowNums^.Ay[RowInx].Number;
  2146.           if (OldSelRow1 <= R) and (R <= OldSelRow2) then
  2147.             for ColInx := 0 to pred(tbColNums^.Count) do
  2148.               begin
  2149.                 C := tbColNums^.Ay[ColInx].Number;
  2150.                 if (OldSelCol1 <= C) and (C <= OldSelCol2) then
  2151.                   begin
  2152.                     DeselCells.DeleteCell(R, C);
  2153.                     NewInvCells.AddCell(R, C);
  2154.                   end;
  2155.               end;
  2156.           end;
  2157.       {for the new selection, for each cell remove it from the new selected
  2158.        cell array; if it wasn't there add it to the same array}
  2159.       for RowInx := 0 to pred(tbRowNums^.Count) do
  2160.         begin
  2161.           R := tbRowNums^.Ay[RowInx].Number;
  2162.           if (NewSelRow1 <= R) and (R <= NewSelRow2) then
  2163.             for ColInx := 0 to pred(tbColNums^.Count) do
  2164.               begin
  2165.                 C := tbColNums^.Ay[ColInx].Number;
  2166.                 if (NewSelCol1 <= C) and (C <= NewSelCol2) then
  2167.                   if not NewInvCells.DeleteCell(R, C) then
  2168.                     NewInvCells.AddCell(R, C);
  2169.               end;
  2170.           end;
  2171.       {add the current active cell to the new selected cell array}
  2172.       NewInvCells.AddCell(ActiveRow, ActiveCol);
  2173.       {merge the cells from the temporary arrays into the main invalid
  2174.        cell array}
  2175.       tbInvCells.Merge(NewInvCells);
  2176.       tbInvCells.Merge(DeselCells);
  2177.     finally
  2178.       NewInvCells.Free;
  2179.       DeselCells.Free
  2180.     end;{try..finally}
  2181.   end;
  2182. {====================================================================}
  2183.  
  2184.  
  2185. {==TOvcTable notification methods====================================}
  2186. procedure TOvcCustomTable.tbCellChanged(Sender : TObject);
  2187.   begin
  2188.     {don't bother if we're being loaded or destroyed}
  2189.     if ((ComponentState * [csLoading, csDestroying]) <> []) then
  2190.       Exit;
  2191.     {if we have a handle repaint the table}
  2192.     if HandleAllocated then
  2193.       begin
  2194.         AllowRedraw := false;
  2195.         try
  2196.           InvalidateTable;
  2197.         finally
  2198.           AllowRedraw := true;
  2199.         end;{try..finally}
  2200.      end;
  2201.   end;
  2202. {--------}
  2203. procedure TOvcCustomTable.tbColChanged(Sender : TObject; ColNum1, ColNum2 : TColNum;
  2204.                                        Action : TOvcTblActions);
  2205.   var
  2206.     CC   : TColNum;
  2207.     DoIt : boolean;
  2208.   begin
  2209.     {don't bother if we're being loaded or destroyed}
  2210.     if ((ComponentState * [csLoading, csDestroying]) <> []) then
  2211.       Exit;
  2212.     {similarly don't bother if we have no handle}
  2213.     if not HandleAllocated then begin
  2214.       tbSelList.SetColCount(ColCount);
  2215.       Exit;
  2216.     end;
  2217.     {make sure there's no flicker}
  2218.     AllowRedraw := false;
  2219.     try
  2220.       {decide whether there's anything to do to the visible display}
  2221.       DoIt := false;
  2222.       with tbColNums^ do
  2223.         case Action of
  2224.           taGeneral : DoIt := true;
  2225.           taSingle  : begin
  2226.                         DoIt := (Ay[0].Number <= ColNum1) and
  2227.                                 (ColNum1 <= Ay[pred(Count)].Number);
  2228.                         {check for unhiding a column after all others}
  2229.                         if not DoIt then
  2230.                           DoIt := (ColNum1 > Ay[pred(Count)].Number) and
  2231.                                   (ClientWidth > Ay[Count].Offset);
  2232.                         DoColumnsChanged(ColNum1, -1, taSingle);
  2233.                       end;
  2234.           taAll     : DoIt := true;
  2235.           taInsert  : begin
  2236.                         DoIt := (Ay[0].Number <= ColNum1) and
  2237.                                 (ColNum1 <= Ay[pred(Count)].Number);
  2238.                         {check for appending a column}
  2239.                         if not DoIt then
  2240.                           DoIt := (ColNum1 > Ay[pred(Count)].Number) and
  2241.                                   (ClientWidth > Ay[Count].Offset);
  2242.                         FCells.InsertCol(ColNum1);
  2243.                         DoColumnsChanged(ColNum1, -1, taInsert);
  2244.                       end;
  2245.           taDelete  : begin
  2246.                         DoIt := (Ay[0].Number <= ColNum1) and
  2247.                                 (ColNum1 <= Ay[pred(Count)].Number);
  2248.                         FCells.DeleteCol(ColNum1);
  2249.                         DoColumnsChanged(ColNum1, -1, taDelete);
  2250.                       end;
  2251.           taExchange: begin
  2252.                         DoIt := (Ay[0].Number <= ColNum1) and
  2253.                                 (ColNum1 <= Ay[pred(Count)].Number);
  2254.                         if not DoIt then
  2255.                           DoIt := (Ay[0].Number <= ColNum2) and
  2256.                                   (ColNum2 <= Ay[pred(Count)].Number);
  2257.                         FCells.ExchangeCols(ColNum1, ColNum2);
  2258.                         DoColumnsChanged(ColNum1, ColNum2, taExchange);
  2259.                       end;
  2260.         end;{case}
  2261.       {if nothing to do to the visible columns, then do it!}
  2262.       if not DoIt then
  2263.         begin
  2264.           {must still reset the horizontal scroll bar even so}
  2265.           tbSelList.SetColCount(ColCount);
  2266.           tbSetScrollRange(otsbHorizontal);
  2267.           tbSetScrollPos(otsbHorizontal);
  2268.           Exit;
  2269.         end;
  2270.       {redisplay the table}
  2271.       tbCalcColData(tbColNums, LeftCol);
  2272.       InvalidateTable;
  2273.       {the column could have changed because it was hidden or deleted...
  2274.        ...must make sure that LeftCol and ActiveCol haven't
  2275.           been hidden as well.}
  2276.       if (Action = taSingle) or (Action = taDelete) then
  2277.         begin
  2278.           if (ColNum1 = LeftCol) then
  2279.             LeftCol := LeftCol; {this does do something!}
  2280.           if (ColNum1 = ActiveCol) then
  2281.             ActiveCol := ActiveCol; {this does do something!}
  2282.         end;
  2283.       {reset the block column values}
  2284.       CC := ColCount;
  2285.       if (CC <= BlockColBegin) then
  2286.         BlockColBegin := pred(CC);
  2287.       if (CC <= BlockColEnd) then
  2288.         BlockColEnd := pred(CC);
  2289.       tbSelList.SetColCount(ColCount);
  2290.       tbSetScrollRange(otsbHorizontal);
  2291.       tbSetScrollPos(otsbHorizontal);
  2292.       if (LeftCol > tbLastLeftCol) then
  2293.         LeftCol := tbLastLeftCol;
  2294.     finally
  2295.       AllowRedraw := true;
  2296.     end;{try..finally}
  2297.   end;
  2298. {--------}
  2299. procedure TOvcCustomTable.tbColorsChanged(Sender : TObject);
  2300.   begin
  2301.     {don't bother if we're being loaded or destroyed}
  2302.     if ((ComponentState * [csLoading, csDestroying]) <> []) then
  2303.       Exit;
  2304.     {if we have a handle repaint the table}
  2305.     if HandleAllocated then
  2306.       begin
  2307.         AllowRedraw := false;
  2308.         try
  2309.           InvalidateTable;
  2310.         finally
  2311.           AllowRedraw := true;
  2312.         end;{try..finally}
  2313.       end;
  2314.   end;
  2315. {--------}
  2316. procedure TOvcCustomTable.tbGridPenChanged(Sender : TObject);
  2317.   begin
  2318.     {don't bother if we're being loaded or destroyed}
  2319.     if ((ComponentState * [csLoading, csDestroying]) <> []) then
  2320.       Exit;
  2321.     {if we have a handle repaint the table}
  2322.     if HandleAllocated then
  2323.       begin
  2324.         AllowRedraw := false;
  2325.         try
  2326.           InvalidateTable;
  2327.         finally
  2328.           AllowRedraw := true;
  2329.         end;{try..finally}
  2330.       end;
  2331.   end;
  2332. {--------}
  2333. procedure TOvcCustomTable.tbRowChanged(Sender : TObject; RowNum1, RowNum2 : TRowNum;
  2334.                                        Action : TOvcTblActions);
  2335.   var
  2336.     RL   : TRowNum;
  2337.     DoIt : boolean;
  2338.   begin
  2339.     {don't bother if we're being loaded or destroyed}
  2340.     if ((ComponentState * [csLoading, csDestroying]) <> []) then
  2341.       Exit;
  2342.     {similarly don't bother if we have no handle}
  2343.     if not HandleAllocated then begin
  2344.       tbSelList.SetRowCount(RowLimit);
  2345.       Exit;
  2346.     end;
  2347.     {make sure there's no flicker}
  2348.     AllowRedraw := false;
  2349.     try
  2350.       {decide whether there's anything to do to the visible display}
  2351.       DoIt := false;
  2352.       with tbRowNums^ do
  2353.         case Action of
  2354.           taGeneral : DoIt := true;
  2355.           taSingle  : begin
  2356.                         DoIt := (Ay[0].Number <= RowNum1) and
  2357.                                 (RowNum1 <= Ay[pred(Count)].Number);
  2358.                         {check for unhiding a row after all others}
  2359.                         if not DoIt then
  2360.                           DoIt := (RowNum1 > Ay[pred(Count)].Number) and
  2361.                                   (ClientHeight > Ay[Count].Offset);
  2362.                         DoRowsChanged(RowNum1, -1, taSingle);
  2363.                       end;
  2364.           taAll     : DoIt := true;
  2365.           taInsert  : begin
  2366.                         DoIt := (Ay[0].Number <= RowNum1) and
  2367.                                 (RowNum1 <= Ay[pred(Count)].Number);
  2368.                         {check for appending a row}
  2369.                         if not DoIt then
  2370.                           DoIt := (RowNum1 > Ay[pred(Count)].Number) and
  2371.                                   (ClientHeight > Ay[Count].Offset);
  2372.                         FCells.InsertRow(RowNum1);
  2373.                         DoRowsChanged(RowNum1, -1, taInsert);
  2374.                       end;
  2375.           taDelete  : begin
  2376.                         DoIt := (Ay[0].Number <= RowNum1) and
  2377.                                 (RowNum1 <= Ay[pred(Count)].Number);
  2378.                         FCells.DeleteRow(RowNum1);
  2379.                         DoRowsChanged(RowNum1, -1, taDelete);
  2380.                       end;
  2381.           taExchange: begin
  2382.                         DoIt := (Ay[0].Number <= RowNum1) and
  2383.                                 (RowNum1 <= Ay[pred(Count)].Number);
  2384.                         if not DoIt then
  2385.                           DoIt := (Ay[0].Number <= RowNum2) and
  2386.                                   (RowNum2 <= Ay[pred(Count)].Number);
  2387.                         FCells.ExchangeRows(RowNum1, RowNum2);
  2388.                         DoRowsChanged(RowNum1, RowNum2, taExchange);
  2389.                       end;
  2390.         end;{case}
  2391.       {if nothing to do to the visible rows, then do it!}
  2392.       if not DoIt then
  2393.         begin
  2394.           {must still reset the vertical scroll bar even so}
  2395.           tbSelList.SetRowCount(RowLimit);
  2396.           tbSetScrollRange(otsbVertical);
  2397.           tbSetScrollPos(otsbVertical);
  2398.           Exit;
  2399.         end;
  2400.       {redisplay the table}
  2401.       tbCalcRowData(tbRowNums, TopRow);
  2402.       InvalidateTable;
  2403.       {the row could have changed because it was hidden or deleted...
  2404.        ...must make sure that TopRow and ActiveRow haven't
  2405.           been hidden as well.}
  2406.       if (Action = taSingle) or (Action = taDelete) then
  2407.         begin
  2408.           if (RowNum1 = TopRow) then
  2409.             TopRow := TopRow; {this does do something!}
  2410.           if (RowNum1 = ActiveRow) then
  2411.             ActiveRow := ActiveRow; {this does do something!}
  2412.         end;
  2413.       {reset the block row values}
  2414.       RL := RowLimit;
  2415.       if (RL <= BlockRowBegin) then
  2416.         BlockRowBegin := pred(RL);
  2417.       if (RL <= BlockRowEnd) then
  2418.         BlockRowEnd := pred(RL);
  2419.       tbSelList.SetRowCount(RowLimit);
  2420.       tbSetScrollRange(otsbVertical);
  2421.       tbSetScrollPos(otsbVertical);
  2422.     finally
  2423.       AllowRedraw := true;
  2424.     end;{try..finally}
  2425.   end;
  2426. {====================================================================}
  2427.  
  2428.  
  2429. {==TOvcTable invalidate cell methods=================================}
  2430. procedure TOvcCustomTable.InvalidateCell(RowNum : TRowNum; ColNum : TColNum);
  2431.   var
  2432.     CInx : integer;
  2433.     RInx : integer;
  2434.   begin
  2435.     RInx := tbFindRowInx(RowNum);
  2436.     if (RInx <> -1) then
  2437.       begin
  2438.         CInx := tbFindColInx(ColNum);
  2439.         if (CInx <> -1) then
  2440.           tbInvCells.AddCell(RowNum, ColNum);
  2441.       end;
  2442.   end;
  2443. {--------}
  2444. procedure TOvcCustomTable.InvalidateCellsInRect(const R : TRect);
  2445.   var
  2446.     GR          : TRect;
  2447.     WhatToPaint : integer;
  2448.     RowInx      : integer;
  2449.     ColInx      : integer;
  2450.   begin
  2451.     WhatToPaint := tbCalcCellsFromRect(R, GR);
  2452.  
  2453.     if (WhatToPaint <> 2) then
  2454.       for RowInx := GR.Top to GR.Bottom do
  2455.         for ColInx := GR.Left to GR.Right do
  2456.           InvalidateCell(tbRowNums^.Ay[RowInx].Number, tbColNums^.Ay[ColInx].Number);
  2457.  
  2458.     if (WhatToPaint <> 0) then
  2459.       tbInvCells.AddUnusedBit;
  2460.   end;
  2461. {--------}
  2462. procedure TOvcCustomTable.InvalidateColumn(ColNum : TColNum);
  2463.   var
  2464.     RowInx : integer;
  2465.     ColInx : integer;
  2466.   begin
  2467.     ColInx := tbFindColInx(ColNum);
  2468.     if (ColInx <> -1) then
  2469.       with tbRowNums^ do
  2470.         for RowInx := 0 to pred(Count) do
  2471.           tbInvCells.AddCell(Ay[RowInx].Number, ColNum);
  2472.   end;
  2473. {--------}
  2474. procedure TOvcCustomTable.tbInvalidateColHdgPrim(ColNum : TColNum; InvCells : TOvcCellArray);
  2475.   var
  2476.     RowInx : integer;
  2477.     ColInx : integer;
  2478.   begin
  2479.     ColInx := tbFindColInx(ColNum);
  2480.     if (ColInx <> -1) then
  2481.       with tbRowNums^ do
  2482.         for RowInx := 0 to pred(LockedRows) do
  2483.           InvCells.AddCell(Ay[RowInx].Number, ColNum);
  2484.   end;
  2485. {--------}
  2486. procedure TOvcCustomTable.InvalidateColumnHeading(ColNum : TColNum);
  2487.   begin
  2488.     tbInvalidateColHdgPrim(ColNum, tbInvCells);
  2489.   end;
  2490. {--------}
  2491. procedure TOvcCustomTable.InvalidateRow(RowNum : TRowNum);
  2492.   var
  2493.     RowInx : integer;
  2494.     ColInx : integer;
  2495.   begin
  2496.     RowInx := tbFindRowInx(RowNum);
  2497.     if (RowInx <> -1) then
  2498.       with tbColNums^ do
  2499.         for ColInx := 0 to pred(Count) do
  2500.           tbInvCells.AddCell(RowNum, Ay[ColInx].Number);
  2501.   end;
  2502. {--------}
  2503. procedure TOvcCustomTable.tbInvalidateRowHdgPrim(RowNum : TRowNum; InvCells : TOvcCellArray);
  2504.   var
  2505.     RowInx : integer;
  2506.     ColInx : integer;
  2507.   begin
  2508.     RowInx := tbFindRowInx(RowNum);
  2509.     if (RowInx <> -1) then
  2510.       with tbColNums^ do
  2511.         for ColInx := 0 to pred(LockedCols) do
  2512.           InvCells.AddCell(RowNum, Ay[ColInx].Number);
  2513.   end;
  2514. {--------}
  2515. procedure TOvcCustomTable.InvalidateRowHeading(RowNum : TRowNum);
  2516.   begin
  2517.     tbInvalidateRowHdgPrim(RowNum, tbInvCells);
  2518.   end;
  2519. {--------}
  2520. procedure TOvcCustomTable.InvalidateTable;
  2521.   var
  2522.     RowInx : integer;
  2523.     ColInx : integer;
  2524.     PredColNumsCount : integer;
  2525.     PredRowNumsCount : integer;
  2526.   begin
  2527.     PredColNumsCount := pred(tbColNums^.Count);
  2528.     PredRowNumsCount := pred(tbRowNums^.Count);
  2529.     for RowInx := 0 to PredRowNumsCount do
  2530.       for ColInx := 0 to PredColNumsCount do
  2531.         tbInvCells.AddCell(tbRowNums^.Ay[RowInx].Number,
  2532.                              tbColNums^.Ay[ColInx].Number);
  2533.     tbInvCells.AddUnusedBit;
  2534.   end;
  2535. {--------}
  2536. procedure TOvcCustomTable.InvalidateTableNotLockedCols;
  2537.   var
  2538.     RowInx      : integer;
  2539.     ColInx      : integer;
  2540.     StartColInx : integer;
  2541.     PredColNumsCount : integer;
  2542.     PredRowNumsCount : integer;
  2543.   begin
  2544.     StartColInx := 0;
  2545.     PredColNumsCount := pred(tbColNums^.Count);
  2546.     PredRowNumsCount := pred(tbRowNums^.Count);
  2547.     while (StartColInx <= PredColNumsCount) and
  2548.           (tbColNums^.Ay[StartColInx].Number < LockedCols) do
  2549.       inc(StartColInx);
  2550.     for RowInx := 0 to PredRowNumsCount do
  2551.       for ColInx := StartColInx to PredColNumsCount do
  2552.         tbInvCells.AddCell(tbRowNums^.Ay[RowInx].Number,
  2553.                              tbColNums^.Ay[ColInx].Number);
  2554.     tbInvCells.AddUnusedBit;
  2555.   end;
  2556. {--------}
  2557. procedure TOvcCustomTable.InvalidateTableNotLockedRows;
  2558.   var
  2559.     RowInx      : integer;
  2560.     ColInx      : integer;
  2561.     StartRowInx : integer;
  2562.     PredColNumsCount : integer;
  2563.     PredRowNumsCount : integer;
  2564.   begin
  2565.     StartRowInx := 0;
  2566.     PredColNumsCount := pred(tbColNums^.Count);
  2567.     PredRowNumsCount := pred(tbRowNums^.Count);
  2568.     while (StartRowInx <= PredRowNumsCount) and
  2569.           (tbRowNums^.Ay[StartRowInx].Number < LockedRows) do
  2570.       inc(StartRowInx);
  2571.     for RowInx := StartRowInx to PredRowNumsCount do
  2572.       for ColInx := 0 to PredColNumsCount do
  2573.         tbInvCells.AddCell(tbRowNums^.Ay[RowInx].Number,
  2574.                              tbColNums^.Ay[ColInx].Number);
  2575.     tbInvCells.AddUnusedBit;
  2576.   end;
  2577. {====================================================================}
  2578.  
  2579.  
  2580. {==TOvcTable miscellaneous===========================================}
  2581. function  TOvcCustomTable.tbCalcActiveCellRect(var ACR : TRect) : boolean;
  2582.   var
  2583.     RInx : integer;
  2584.     CInx : integer;
  2585.   begin
  2586.     Result := false;
  2587.     RInx := tbFindRowInx(ActiveRow);
  2588.     if (RInx = -1) then
  2589.       Exit;
  2590.     CInx := tbFindColInx(ActiveCol);
  2591.     if (CInx = -1) then
  2592.       Exit;
  2593.  
  2594.     Result := true;
  2595.     with ACR do
  2596.       begin
  2597.         Top := tbRowNums^.Ay[RInx].Offset;
  2598.         Bottom := tbRowNums^.Ay[succ(RInx)].Offset;
  2599.         Left := tbColNums^.Ay[CInx].Offset;
  2600.         Right := tbColNums^.Ay[succ(CInx)].Offset;
  2601.       end;
  2602.     with GridPenSet.NormalGrid do
  2603.       case Effect of
  2604.         geVertical   : dec(ACR.Right);
  2605.         geHorizontal : dec(ACR.Bottom);
  2606.         geBoth       : begin
  2607.                          dec(ACR.Right);
  2608.                          dec(ACR.Bottom);
  2609.                        end;
  2610.         ge3D         : InflateRect(ACR, -1, -1);
  2611.       end;{case}
  2612.   end;
  2613. {--------}
  2614. function TOvcCustomTable.tbCalcCellsFromRect(const UR : TRect; var GR : TRect) : integer;
  2615.   {-Converts a paint rect into a 'grid' rect. A grid rect is a rectangle of
  2616.     cells, defined by their display indexes rather than their row/column
  2617.     numbers.
  2618.     The function result is a definition of the type of rectangle produced:
  2619.       0--top left and bottom right corners of the original rect are
  2620.          exclusively within the table;
  2621.       1--top left of the rect is in the displayed table, the bottom right is
  2622.          in the 'unused' bit (the bit between the displayed cells and the
  2623.          client area;
  2624.       2--the original rectangle is exclusively in the 'unused bit'.
  2625.     }
  2626.   var
  2627.     Row : TRowNum;
  2628.     Col : TColNum;
  2629.     Region : TOvcTblRegion;
  2630.   begin
  2631.     Result := 0;
  2632.     Region := CalcRowColFromXY(UR.Left, UR.Top, Row, Col);
  2633.     if (Region = otrInUnused) then
  2634.       begin
  2635.         Result := 2;
  2636.         FillChar(GR, sizeof(GR), $FF); {set 'em all to -1}
  2637.         Exit;
  2638.       end;
  2639.     GR.Left := tbFindColInx(Col);
  2640.     GR.Top := tbFindRowInx(Row);
  2641.     Region := CalcRowColFromXY(UR.Right, UR.Bottom, Row, Col);
  2642.     if (Region = otrInUnused) or (Region = otrOutside) then
  2643.       Result := 1;
  2644.     if (Col = CRCFXY_ColToRight) then
  2645.       GR.Right := pred(tbColNums^.Count)
  2646.     else
  2647.       GR.Right := tbFindColInx(Col);
  2648.     if (Row = CRCFXY_RowBelow) then
  2649.       GR.Bottom := pred(tbRowNums^.Count)
  2650.     else
  2651.       GR.Bottom := tbFindRowInx(Row);
  2652.   end;
  2653. {--------}
  2654. procedure TOvcCustomTable.tbCalcColData(var CD : POvcTblDisplayArray;
  2655.                                             NewLeftCol : TColNum);
  2656.   var
  2657.     X      : integer;
  2658.     Width  : integer;
  2659.     Access : TOvcTblAccess;
  2660.     Hidden : boolean;
  2661.     ColNum : TColNum;
  2662.     FullWidth    : integer;
  2663.     PredColCount : TColNum;
  2664.     PredLocked   : TColNum;
  2665.   begin
  2666.     {initialise}
  2667.     X := 0;
  2668.     ColNum := -1;
  2669.     CD^.Count := 0;
  2670.     FullWidth := ClientWidth;              {save expense of function call in loop}
  2671.     PredColCount := pred(ColCount);        {save expense of function call in loop}
  2672.     PredLocked := pred(LockedCols);        {save expense of function call in loop}
  2673.  
  2674.     {deal with the locked columns first}
  2675.     if (LockedCols <> 0) then
  2676.       while (X < FullWidth) and (ColNum < PredLocked) do
  2677.         begin
  2678.           inc(ColNum);
  2679.           tbQueryColData(ColNum, Width, Access, Hidden);
  2680.           if not Hidden then
  2681.             begin
  2682.               with CD^ do
  2683.                 begin
  2684.                   with Ay[Count] do
  2685.                     begin
  2686.                       Number := ColNum;
  2687.                       Offset := X;
  2688.                     end;
  2689.                   inc(Count);
  2690.                   if (Count >= AllocNm) then
  2691.                     AssignDisplayArray(CD, AllocNm+16);
  2692.                 end;
  2693.               inc(X, Width);
  2694.             end;
  2695.         end;
  2696.  
  2697.     {now deal with the rightmost columns}
  2698.     ColNum := pred(NewLeftCol);
  2699.     while (X < FullWidth) and (ColNum < PredColCount) do
  2700.       begin
  2701.         inc(ColNum);
  2702.         tbQueryColData(ColNum, Width, Access, Hidden);
  2703.         if not Hidden then
  2704.           begin
  2705.             with CD^ do
  2706.               begin
  2707.                 with Ay[Count] do
  2708.                   begin
  2709.                     Number := ColNum;
  2710.                     Offset := X;
  2711.                   end;
  2712.                 inc(Count);
  2713.                 if (Count >= AllocNm) then
  2714.                   AssignDisplayArray(CD, AllocNm+16);
  2715.               end;
  2716.             inc(X, Width);
  2717.           end;
  2718.       end;
  2719.  
  2720.     {use the next spare element for storing the offset for the grid}
  2721.     with CD^ do
  2722.       Ay[Count].Offset := X;
  2723.   end;
  2724. {--------}
  2725. function TOvcCustomTable.CalcRowColFromXY(X, Y : integer;
  2726.                                       var RowNum : TRowNum;
  2727.                                       var ColNum : TColNum) : TOvcTblRegion;
  2728.   var
  2729.     ColInx : integer;
  2730.     RowInx : integer;
  2731.     CW     : integer;
  2732.     CH     : integer;
  2733.     TW     : integer;
  2734.     TH     : integer;
  2735.   begin
  2736.     RowNum := CRCFXY_RowBelow;
  2737.     ColNum := CRCFXY_ColToRight;
  2738.     CW := ClientWidth;
  2739.     CH := ClientHeight;
  2740.  
  2741.     {calculate the table width and height}
  2742.     with tbColNums^ do
  2743.       TW := MinI(CW, Ay[Count].Offset);
  2744.     with tbRowNums^ do
  2745.       TH := MinI(CH, Ay[Count].Offset);
  2746.  
  2747.     {make a first pass at calculating the region}
  2748.     if (X < 0) or (Y < 0) or (X >= CW) or (Y >= CH) then
  2749.       Result := otrOutside {definitely}
  2750.     else
  2751.       Result := otrInMain; {possibly, could also be one of the other two}
  2752.  
  2753.     {calculate row first}
  2754.     with tbRowNums^ do
  2755.       if (0 <= Y) and (Y < TH) then
  2756.         begin
  2757.           RowInx := 0;
  2758.           while (Ay[RowInx].Offset <= Y) do
  2759.             inc(RowInx);
  2760.           RowNum := Ay[pred(RowInx)].Number;
  2761.         end;
  2762.  
  2763.     {now calculate column}
  2764.     with tbColNums^ do
  2765.       if (0 <= X) and (X < TW) then
  2766.         begin
  2767.           ColInx := 0;
  2768.           while (Ay[ColInx].Offset <= X) do
  2769.             inc(ColInx);
  2770.           ColNum := Ay[pred(ColInx)].Number;
  2771.         end;
  2772.  
  2773.      {now patch up the region}
  2774.      if (Result = otrInMain) then
  2775.        if (RowNum = CRCFXY_RowBelow) or (ColNum = CRCFXY_ColToRight) then
  2776.          Result := otrInUnused
  2777.        else if (RowNum < LockedRows) or (ColNum < LockedCols) then
  2778.          Result := otrInLocked;
  2779.  
  2780.      {now patch up the row and column numbers}
  2781.      if (Result = otrOutside) or (Result = otrInUnused) then
  2782.        begin
  2783.          if (RowNum = CRCFXY_RowBelow) and (Y < 0) then
  2784.            RowNum := CRCFXY_RowAbove;
  2785.          if (ColNum = CRCFXY_ColToRight) and (X < 0) then
  2786.            ColNum := CRCFXY_ColToLeft;
  2787.        end;
  2788.   end;
  2789. {--------}
  2790. {$IFDEF SuppressWarnings}
  2791. {$Warnings OFF}
  2792. {$ENDIF}
  2793. procedure TOvcCustomTable.tbCalcColsOnLastPage;
  2794.   var
  2795.     CD         : POvcTblDisplayArray;
  2796.     OldLeftCol : TColNum;
  2797.     NewLeftCol : TColNum;
  2798.     StillGoing : boolean;
  2799.   begin
  2800.     OldLeftCol := 0;
  2801.     if (ColCount <= LockedCols) then
  2802.       begin
  2803.         tbColsOnLastPage := 0;
  2804.         Exit;
  2805.       end;
  2806.  
  2807.     CD := nil;
  2808.     AssignDisplayArray(CD, tbColNums^.AllocNm);
  2809.  
  2810.     try
  2811.       NewLeftCol := IncCol(pred(ColCount), 0);
  2812.       tbCalcColData(CD, NewLeftCol);
  2813.       if (CD^.Ay[CD^.Count].Offset > ClientWidth) then
  2814.         begin
  2815.           tbLastLeftCol := NewLeftCol;
  2816.           tbColsOnLastPage := 1;
  2817.           Exit;
  2818.         end;
  2819.  
  2820.       StillGoing := true;
  2821.       while StillGoing do
  2822.         begin
  2823.           OldLeftCol := NewLeftCol;
  2824.           NewLeftCol := IncCol(NewLeftCol, -1);
  2825.           if (NewLeftCol = OldLeftCol) then
  2826.             StillGoing := false
  2827.           else
  2828.             begin
  2829.               tbCalcColData(CD, NewLeftCol);
  2830.               StillGoing := (CD^.Ay[CD^.Count].Offset < ClientWidth);
  2831.             end;
  2832.         end;
  2833.       tbColsOnLastPage := ColCount - NewLeftCol;
  2834.       tbLastLeftCol := OldLeftCol;
  2835.       if tbLastLeftCol < LeftCol then
  2836.         LeftCol := tbLastLeftCol;
  2837.     finally
  2838.       AssignDisplayArray(CD, 0);
  2839.     end;{try..finally}
  2840.   end;
  2841. {$IFDEF SuppressWarnings}
  2842. {$Warnings ON}
  2843. {$ENDIF}
  2844. {--------}
  2845. procedure TOvcCustomTable.tbCalcRowData(var RD : POvcTblDisplayArray;
  2846.                                             NewTopRow : TRowNum);
  2847.   var
  2848.     Y      : integer;
  2849.     Height : integer;
  2850.     Hidden : boolean;
  2851.     RowNum : TRowNum;
  2852.     FullHeight   : integer;
  2853.     PredRowLimit : TRowNum;
  2854.     PredLocked   : TRowNum;
  2855.   begin
  2856.     {initialise}
  2857.     Y := 0;
  2858.     RowNum := -1;
  2859.     RD^.Count := 0;
  2860.     FullHeight := ClientHeight;            {save expense of function call in loop}
  2861.     PredRowLimit := pred(RowLimit);        {save expense of function call in loop}
  2862.     PredLocked := pred(LockedRows);        {save expense of function call in loop}
  2863.  
  2864.     {deal with the locked rows first}
  2865.     if (LockedRows <> 0) then
  2866.       while (Y < FullHeight) and (RowNum < PredLocked) do
  2867.         begin
  2868.           inc(RowNum);
  2869.           tbQueryRowData(RowNum, Height, Hidden);
  2870.           if not Hidden then
  2871.             begin
  2872.               with RD^ do
  2873.                 begin
  2874.                   with Ay[Count] do
  2875.                     begin
  2876.                       Number := RowNum;
  2877.                       Offset := Y;
  2878.                     end;
  2879.                   inc(Count);
  2880.                   if (Count >= AllocNm) then
  2881.                     AssignDisplayArray(RD, AllocNm+16);
  2882.                 end;
  2883.               inc(Y, Height);
  2884.             end;
  2885.         end;
  2886.  
  2887.     {now deal with the rows underneath the fixed rows}
  2888.     RowNum := pred(NewTopRow);
  2889.     while (Y < FullHeight) and (RowNum < PredRowLimit) do
  2890.       begin
  2891.         inc(RowNum);
  2892.         tbQueryRowData(RowNum, Height, Hidden);
  2893.         if not Hidden then
  2894.           begin
  2895.             with RD^ do
  2896.               begin
  2897.                 with Ay[Count] do
  2898.                   begin
  2899.                     Number := RowNum;
  2900.                     Offset := Y;
  2901.                   end;
  2902.                 inc(Count);
  2903.                 if (Count >= AllocNm) then
  2904.                   AssignDisplayArray(RD, AllocNm+16);
  2905.               end;
  2906.             inc(Y, Height);
  2907.           end;
  2908.       end;
  2909.  
  2910.     {use the next spare element for storing the offset for the grid}
  2911.     with RD^ do
  2912.       Ay[Count].Offset := Y;
  2913.   end;
  2914. {--------}
  2915. {$IFDEF SuppressWarnings}
  2916. {$Warnings OFF}
  2917. {$ENDIF}
  2918. procedure TOvcCustomTable.tbCalcRowsOnLastPage;
  2919.   var
  2920.     RD         : POvcTblDisplayArray;
  2921.     OldTopRow  : TRowNum;
  2922.     NewTopRow  : TRowNum;
  2923.     StillGoing : boolean;
  2924.   begin
  2925.     OldTopRow := 0;
  2926.     if (RowLimit <= LockedRows) then
  2927.       begin
  2928.         tbRowsOnLastPage := 0;
  2929.         Exit;
  2930.       end;
  2931.  
  2932.     RD := nil;
  2933.     AssignDisplayArray(RD, tbRowNums^.AllocNm);
  2934.  
  2935.     try
  2936.       NewTopRow := IncRow(pred(RowLimit), 0);
  2937.       tbCalcRowData(RD, NewTopRow);
  2938.       if (RD^.Ay[RD^.Count].Offset >= ClientHeight) then
  2939.         begin
  2940.           tbLastTopRow := NewTopRow;
  2941.           tbRowsOnLastPage := 1;
  2942.           Exit;
  2943.         end;
  2944.  
  2945.       StillGoing := true;
  2946.       while StillGoing do
  2947.         begin
  2948.           OldTopRow := NewTopRow;
  2949.           NewTopRow := IncRow(OldTopRow, -1);
  2950.           if (NewTopRow = OldTopRow) then
  2951.             StillGoing := false
  2952.           else
  2953.             begin
  2954.               tbCalcRowData(RD, NewTopRow);
  2955.               StillGoing := (RD^.Ay[RD^.Count].Offset < ClientHeight);
  2956.             end;
  2957.         end;
  2958.       tbRowsOnLastPage := RowLimit - OldTopRow;
  2959.       tbLastTopRow := OldTopRow;
  2960.       if tbLastTopRow < TopRow then
  2961.         TopRow := tbLastTopRow;
  2962.     finally
  2963.       AssignDisplayArray(RD, 0);
  2964.     end;{try..finally}
  2965.   end;
  2966. {$IFDEF SuppressWarnings}
  2967. {$Warnings ON}
  2968. {$ENDIF}
  2969. {--------}
  2970. procedure TOvcCustomTable.tbCalcHSBarPosCount;
  2971.   var
  2972.     Col : TColNum;
  2973.   begin
  2974.     tbHSBarPosCount := 0;
  2975.     for Col := LockedCols to tbLastLeftCol do
  2976.       if not tbIsColHidden(Col) then
  2977.         inc(tbHSBarPosCount);
  2978.   end;
  2979. {--------}
  2980. function TOvcCustomTable.tbCalcRequiresVSBar : boolean;
  2981.   var
  2982.     Row : TRowNum;
  2983.   begin
  2984.     {a fast check for possible hidden rows: if there are none and the
  2985.      last page's top row is not equal to the number of locked rows
  2986.      then obviously a vertical scrollbar is required.}
  2987.     if (LockedRows < tbLastTopRow) and
  2988.        (Rows.Count = 0) then
  2989.       begin
  2990.         Result := true;
  2991.         Exit;
  2992.       end;
  2993.     {otherwise check to see whether all rows between the locked rows
  2994.      and the last page's top row are hidden: if so no vertical scroll
  2995.      bar is required.}
  2996.     Result := false;
  2997.     for Row := LockedRows to pred(tbLastTopRow) do
  2998.       if not Rows.Hidden[Row] then
  2999.         begin
  3000.           Result := true;
  3001.           Exit;
  3002.         end;
  3003.   end;
  3004. {--------}
  3005. procedure TOvcCustomTable.ChangeScale(M, D : integer);
  3006.   var
  3007.     i : TColNum;
  3008.   begin
  3009.     inherited ChangeScale(M, D);
  3010.     if (M <> D) then
  3011.       begin
  3012.         Rows.rwScaleHeights(M, D);
  3013.         for i := 0 to pred(ColCount) do
  3014.           with Columns[i] do
  3015.             Width := MulDiv(Width, M, D);
  3016.       end;
  3017.   end;
  3018. {--------}
  3019. function  TOvcCustomTable.tbEditCellHasFocus(FocusHandle : HWND) : boolean;
  3020.   var
  3021.     ChildHandle : HWND;
  3022.   begin
  3023.     Result := false;
  3024.     if not InEditingState then
  3025.       Exit;
  3026.     if (tbActCell.EditHandle = 0) then
  3027.       Exit;
  3028.     Result := true;
  3029.     if (FocusHandle = tbActCell.EditHandle) then
  3030.       Exit;
  3031.     ChildHandle := GetWindow(tbActCell.EditHandle, GW_CHILD);
  3032.     while (ChildHandle <> 0) do
  3033.       begin
  3034.         if (FocusHandle = ChildHandle) then
  3035.           Exit;
  3036.         ChildHandle := GetWindow(ChildHandle, GW_CHILD);
  3037.       end;
  3038.     Result := false;
  3039.   end;
  3040. {--------}
  3041. procedure TOvcCustomTable.tbEnsureColumnIsVisible(ColNum : TColNum);
  3042.   var
  3043.     ColInx : integer;
  3044.     CW     : integer;
  3045.     FarRight : integer;
  3046.     LeftInx  : integer;
  3047.     LColOfs  : integer;
  3048.     LColWd   : integer;
  3049.   begin
  3050.     {get the index for the column}
  3051.     ColInx := tbFindColInx(ColNum);
  3052.     if (ColInx = -1) then
  3053.       begin
  3054.         {the column is not even visible}
  3055.         {make this column the left column}
  3056.         LeftCol := ColNum;
  3057.       end
  3058.     else
  3059.       begin
  3060.         CW := ClientWidth;
  3061.         with tbColNums^ do
  3062.           FarRight := Ay[succ(ColInx)].Offset;
  3063.         if (FarRight > CW) then
  3064.           begin
  3065.             {the column is partially visible}
  3066.  
  3067.             {pretend that we're scrolling the table left
  3068.              column by column, until either
  3069.                (1) the column we want is fully visible, or
  3070.                (2) the column we want is the leftmost column
  3071.              then set the leftmost column}
  3072.             LeftInx := tbFindColInx(LeftCol);
  3073.             LColOfs := tbColNums^.Ay[LeftInx].Offset;
  3074.             LColWd := tbColNums^.Ay[succ(LeftInx)].Offset - LColOfs;
  3075.             dec(FarRight, LColWd);
  3076.             inc(LColOfs, LColWd);
  3077.             inc(LeftInx);
  3078.             while (LeftInx < ColInx) and (FarRight > CW) do
  3079.               begin
  3080.                 LColWd := tbColNums^.Ay[succ(LeftInx)].Offset - LColOfs;
  3081.                 dec(FarRight, LColWd);
  3082.                 inc(LColOfs, LColWd);
  3083.                 inc(LeftInx);
  3084.               end;
  3085.             if (LeftInx < tbColNums^.Count) then
  3086.               LeftCol := tbColNums^.Ay[LeftInx].Number;
  3087.           end;
  3088.       end;
  3089.   end;
  3090. {--------}
  3091. procedure TOvcCustomTable.tbEnsureRowIsVisible(RowNum : TRowNum);
  3092.   var
  3093.     RowInx : integer;
  3094.     CH     : integer;
  3095.     FarBottom: integer;
  3096.     TopInx   : integer;
  3097.     TpRowOfs : integer;
  3098.     TpRowHt  : integer;
  3099.   begin
  3100.     RowInx := tbFindRowInx(RowNum);
  3101.     if (RowInx = -1) then
  3102.       begin
  3103.         {the row is not even visible}
  3104.         {make this row the top row}
  3105.         TopRow := RowNum;
  3106.       end
  3107.     else
  3108.       begin
  3109.         CH := ClientHeight;
  3110.         with tbRowNums^ do
  3111.           FarBottom := Ay[succ(RowInx)].Offset;
  3112.         if (FarBottom > CH) then
  3113.           begin
  3114.             {the row is partially visible}
  3115.  
  3116.             {pretend that we're scrolling the table up
  3117.              row by row, until either
  3118.                (1) the row we want is fully visible, or
  3119.                (2) the row we want is the topmost row
  3120.              then set the topmost row}
  3121.             TopInx := tbFindRowInx(TopRow);
  3122.             TpRowOfs := tbRowNums^.Ay[TopInx].Offset;
  3123.             TpRowHt := tbRowNums^.Ay[succ(TopInx)].Offset - TpRowOfs;
  3124.             dec(FarBottom, TpRowHt);
  3125.             inc(TpRowOfs, TpRowHt);
  3126.             inc(TopInx);
  3127.             while (TopInx < RowInx) and (FarBottom > CH) do
  3128.               begin
  3129.                 TpRowHt := tbRowNums^.Ay[succ(TopInx)].Offset - TpRowOfs;
  3130.                 dec(FarBottom, TpRowHt);
  3131.                 inc(TpRowOfs, TpRowHt);
  3132.                 inc(TopInx);
  3133.               end;
  3134.             if (TopInx < tbRowNums^.Count) then
  3135.               TopRow := tbRowNums^.Ay[TopInx].Number;
  3136.           end;
  3137.       end;
  3138.   end;
  3139. {--------}
  3140. function TOvcCustomTable.tbFindCell(RowNum : TRowNum;
  3141.                                     ColNum : TColNum) : TOvcBaseTableCell;
  3142.   begin
  3143.     Result := FCells[RowNum, ColNum];
  3144.     if not Assigned(Result) then
  3145.       if (RowNum < LockedRows) then
  3146.         Result := FLockedRowsCell
  3147.       else
  3148.         Result := FCols[ColNum].DefaultCell;
  3149.   end;
  3150. {--------}
  3151. function  TOvcCustomTable.tbFindColInx(ColNum : TColNum) : integer;
  3152.   var
  3153.     L, M, R   : integer;
  3154.     CurNumber : TColNum;
  3155.   begin
  3156.     Result := -1;
  3157.     with tbColNums^ do
  3158.       begin
  3159.         if (Count = 0) then
  3160.           Exit;
  3161.         L := 0;
  3162.         R := pred(Count);
  3163.         repeat
  3164.           M := (L + R) div 2;
  3165.           CurNumber := Ay[M].Number;
  3166.           if (ColNum = CurNumber) then
  3167.             begin
  3168.               Result := M;
  3169.               Exit;
  3170.             end
  3171.           else if (ColNum < CurNumber) then
  3172.             R := pred(M)
  3173.           else
  3174.             L := succ(M);
  3175.         until (L > R);
  3176.       end;
  3177.   end;
  3178. {--------}
  3179. function TOvcCustomTable.tbFindRowInx(RowNum : TRowNum) : integer;
  3180.   var
  3181.     L, M, R   : integer;
  3182.     CurNumber : TRowNum;
  3183.   begin
  3184.     Result := -1;
  3185.     with tbRowNums^ do
  3186.       begin
  3187.         if (Count = 0) then
  3188.           Exit;
  3189.         L := 0;
  3190.         R := pred(Count);
  3191.         repeat
  3192.           M := (L + R) div 2;
  3193.           CurNumber := Ay[M].Number;
  3194.           if (RowNum = CurNumber) then
  3195.             begin
  3196.               Result := M;
  3197.               Exit;
  3198.             end
  3199.           else if (RowNum < CurNumber) then
  3200.             R := pred(M)
  3201.           else
  3202.             L := succ(M);
  3203.         until (L > R);
  3204.       end;
  3205.   end;
  3206. {--------}
  3207. procedure TOvcCustomTable.GetDisplayedColNums(var NA : TOvcTableNumberArray);
  3208.   var
  3209.     i : integer;
  3210.     WorkCount : integer;
  3211.   begin
  3212.     WorkCount := MinL(NA.NumElements, tbColNums^.Count);
  3213.     for i := 0 to pred(WorkCount) do
  3214.       NA.Number[i] := tbColNums^.Ay[i].Number;
  3215.     NA.Count := tbColNums^.Count
  3216.   end;
  3217. {--------}
  3218. procedure TOvcCustomTable.GetDisplayedRowNums(var NA : TOvcTableNumberArray);
  3219.   var
  3220.     i : integer;
  3221.     WorkCount : integer;
  3222.   begin
  3223.     WorkCount := MinL(NA.NumElements, tbRowNums^.Count);
  3224.     for i := 0 to pred(WorkCount) do
  3225.       NA.Number[i] := tbRowNums^.Ay[i].Number;
  3226.     NA.Count := tbRowNums^.Count
  3227.   end;
  3228. {--------}
  3229. function TOvcCustomTable.IncCol(ColNum : TColNum; Direction : integer) : TColNum;
  3230.   {-Return a valid unhidden column number. If Direction is:
  3231.       -ve : start at C and find the previous unhidden column number, if there
  3232.             is none previous to this one, return C.
  3233.       +ve : start at R and find the next unhidden column number, if there is
  3234.             none after this one, return C
  3235.         0 : verify that C is unhidden, if not find the next unhidden column
  3236.             number, if none after this one, find the previous one. If still
  3237.             none, return C.}
  3238.   var
  3239.     CL, CC : TColNum;
  3240.   begin
  3241.     {save the values of properties in local variables}
  3242.     CL := LockedCols;
  3243.     CC := ColCount;
  3244.     {adjust ColNum to be in range}
  3245.     if (ColNum < CL) or (ColNum >= CC) then
  3246.       ColNum := CL;
  3247.     {first direction=0, ie to see whether the column is visible}
  3248.     Result := ColNum;
  3249.     if (Direction = 0) then {check not hidden}
  3250.       if not tbIsColHidden(Result) then
  3251.         Exit;
  3252.     {now direction>=0, ie to increment the column number}
  3253.     if (Direction >= 0) then {go forwards}
  3254.       begin
  3255.         inc(Result);
  3256.         while Result < CC do
  3257.           begin
  3258.             if not tbIsColHidden(Result) then
  3259.               Exit;
  3260.             inc(Result);
  3261.           end;
  3262.         Result := ColNum;
  3263.       end;
  3264.     {now direction<=0, ie to decrement the column number}
  3265.     if (Direction <= 0) then {go backwards}
  3266.       begin
  3267.         dec(Result);
  3268.         while (Result >= CL) do
  3269.           begin
  3270.             if not tbIsColHidden(Result) then
  3271.               Exit;
  3272.             dec(Result);
  3273.           end;
  3274.         Result := ColNum;
  3275.       end;
  3276.   end;
  3277. {--------}
  3278. function TOvcCustomTable.IncRow(RowNum : TRowNum; Direction : integer) : TRowNum;
  3279.   {-Return a valid unhidden row number. If Direction is:
  3280.       -ve : start at R and find the previous unhidden row number, if there
  3281.             is none previous to this one, return R.
  3282.       +ve : start at R and find the next unhidden row number, if there is
  3283.             none after this one, return R
  3284.         0 : verify that R is unhidden, if not find the next unhidden row
  3285.             number, if none after this one, find the previous one. If still
  3286.             none, return R.}
  3287.   var
  3288.     RL, RC : TRowNum;
  3289.   begin
  3290.     {save the values of properties in local variables}
  3291.     RL := LockedRows;
  3292.     RC := RowLimit;
  3293.     {adjust RowNum to be in range}
  3294.     if (RowNum < RL) or (RowNum >= RC) then
  3295.       RowNum := RL;
  3296.     {first direction=0, ie to see whether the column is visible}
  3297.     Result := RowNum;
  3298.     if (Direction = 0) then {check not hidden}
  3299.       if not tbIsRowHidden(Result) then
  3300.         Exit;
  3301.     {now direction>=0, ie to increment the column number}
  3302.     if (Direction >= 0) then {go forwards}
  3303.       begin
  3304.         inc(Result);
  3305.         while (Result < RC) do
  3306.           begin
  3307.             if not tbIsRowHidden(Result) then
  3308.               Exit;
  3309.             inc(Result);
  3310.           end;
  3311.         Result := RowNum;
  3312.       end;
  3313.     {now direction<=0, ie to decrement the column number}
  3314.     if (Direction <= 0) then {go backwards}
  3315.       begin
  3316.         dec(Result);
  3317.         while (Result >= RL) do
  3318.           begin
  3319.             if not tbIsRowHidden(Result) then
  3320.               Exit;
  3321.             dec(Result);
  3322.           end;
  3323.         Result := RowNum;
  3324.       end;
  3325.   end;
  3326. {--------}
  3327. function TOvcCustomTable.InEditingState : boolean;
  3328.   begin
  3329.     Result := (tbState * [otsEditing, otsHiddenEdit]) <> [];
  3330.   end;
  3331. {--------}
  3332. function TOvcCustomTable.tbIsColHidden(ColNum : TColNum) : boolean;
  3333.   begin
  3334.     Result := FCols[ColNum].Hidden;
  3335.   end;
  3336. {--------}
  3337. function TOvcCustomTable.tbIsOnGridLine(MouseX, MouseY : integer;
  3338.                                     var VerticalGrid : boolean) : boolean;
  3339.   var
  3340.     GridLine : integer;
  3341.     Inx      : integer;
  3342.     LockedColsOffset : integer;
  3343.     LockedRowsOffset : integer;
  3344.   begin
  3345.     Result := false;
  3346.     {calc the offsets of the column and row}
  3347.     LockedColsOffset := -1;
  3348.     Inx := 0;
  3349.     with tbColNums^ do
  3350.       while (Inx < Count) do
  3351.         begin
  3352.           if (Ay[Inx].Number >= LockedCols) then
  3353.             Break;
  3354.           inc(Inx);
  3355.           LockedColsOffset := Ay[Inx].Offset;
  3356.         end;
  3357.     LockedRowsOffset := -1;
  3358.     Inx := 0;
  3359.     with tbRowNums^ do
  3360.       while (Inx < Count) do
  3361.         begin
  3362.           if (Ay[Inx].Number >= LockedRows) then
  3363.             Break;
  3364.           inc(Inx);
  3365.           LockedRowsOffset := Ay[Inx].Offset;
  3366.         end;
  3367.     {do the obvious test: cursor is not within the locked area}
  3368.     if (MouseX >= LockedColsOffset) and (MouseY >= LockedRowsOffset) then
  3369.       Exit;
  3370.     {check rows first}
  3371.     if (MouseX < LockedColsOffset) then
  3372.       begin
  3373.         Inx := 0;
  3374.         with tbRowNums^ do
  3375.           while (Inx < Count) do
  3376.             begin
  3377.               inc(Inx);
  3378.               GridLine := Ay[Inx].Offset;
  3379.               if (GridLine-2 <= MouseY) and (MouseY <= GridLine+2) then
  3380.                 begin
  3381.                   VerticalGrid := false;
  3382.                   Result := true;
  3383.                   tbSizeIndex := pred(Inx);
  3384.                   Exit;
  3385.                 end;
  3386.             end;
  3387.       end;
  3388.     {check columns next}
  3389.     if (MouseY < LockedRowsOffset) then
  3390.       begin
  3391.         Inx := 0;
  3392.         with tbColNums^ do
  3393.           while (Inx < Count) do
  3394.             begin
  3395.               inc(Inx);
  3396.               GridLine := Ay[Inx].Offset;
  3397.               if (GridLine-2 <= MouseX) and (MouseX <= GridLine+2) then
  3398.                 begin
  3399.                   VerticalGrid := true;
  3400.                   Result := true;
  3401.                   tbSizeIndex := pred(Inx);
  3402.                   Exit;
  3403.                 end;
  3404.             end;
  3405.       end;
  3406.   end;
  3407. {--------}
  3408. function TOvcCustomTable.tbIsInMoveArea(MouseX, MouseY : integer;
  3409.                                     var IsColMove : boolean) : boolean;
  3410.   var
  3411.     Inx              : integer;
  3412.     LockedColsOffset : integer;
  3413.     LockedRowsOffset : integer;
  3414.   begin
  3415.     Result := false;
  3416.     IsColMove := false;
  3417.     {calc the offsets of the column and row}
  3418.     LockedColsOffset := -1;
  3419.     Inx := 0;
  3420.     with tbColNums^ do
  3421.       while (Inx < Count) do
  3422.         begin
  3423.           if (Ay[Inx].Number >= LockedCols) then
  3424.             Break;
  3425.           inc(Inx);
  3426.           LockedColsOffset := Ay[Inx].Offset;
  3427.         end;
  3428.     LockedRowsOffset := -1;
  3429.     Inx := 0;
  3430.     with tbRowNums^ do
  3431.       while (Inx < Count) do
  3432.         begin
  3433.           if (Ay[Inx].Number >= LockedRows) then
  3434.             Break;
  3435.           inc(Inx);
  3436.           LockedRowsOffset := Ay[Inx].Offset;
  3437.         end;
  3438.     {do the obvious test: cursor is not within the locked area}
  3439.     if (MouseX >= LockedColsOffset) and (MouseY >= LockedRowsOffset) then
  3440.       Exit;
  3441.     {the cursor is within the column move area if it's in a locked cell
  3442.      above the main area of the table; otherwise the cursor is within the
  3443.      row move area if it's in a locked cell to the left of the main area
  3444.      of the table}
  3445.     Result := (MouseX >= LockedColsOffset) and (MouseY < LockedRowsOffset) and
  3446.               (MouseX < tbColNums^.Ay[tbColNums^.Count].Offset);
  3447.     if Result then
  3448.       IsColMove := true
  3449.     else
  3450.       Result := (MouseX < LockedColsOffset) and (MouseY >= LockedRowsOffset) and
  3451.                 (MouseY < tbRowNums^.Ay[tbRowNums^.Count].Offset);
  3452.   end;
  3453. {--------}
  3454. function TOvcCustomTable.tbIsRowHidden(RowNum : TRowNum) : boolean;
  3455.   begin
  3456.     Result := Rows[RowNum].Hidden;
  3457.   end;
  3458. {--------}
  3459. procedure TOvcCustomTable.Notification(AComponent: TComponent; Operation: TOperation);
  3460.   begin
  3461.     inherited Notification(AComponent, Operation);
  3462.     if (AComponent is TOvcBaseTableCell) and (Operation = opRemove) then
  3463.       begin
  3464.         AllowRedraw := false;
  3465.         try
  3466.           if (FLockedRowsCell = TOvcBaseTableCell(AComponent)) then
  3467.             begin
  3468.               FLockedRowsCell.DecRefs;
  3469.               FLockedRowsCell := nil;
  3470.               tbCellChanged(Self);
  3471.             end;
  3472.           if Assigned(FCols) then
  3473.             FCols.tcNotifyCellDeletion(TOvcBaseTableCell(AComponent));
  3474.           if Assigned(FCells) then
  3475.             FCells.tcNotifyCellDeletion(TOvcBaseTableCell(AComponent));
  3476.         finally
  3477.           AllowRedraw := true;
  3478.         end;{try..finally}
  3479.       end;
  3480.   end;
  3481. {--------}
  3482. procedure TOvcCustomTable.tbQueryColData(ColNum : TColNum;
  3483.                                      var W : integer;
  3484.                                      var A : TOvcTblAccess;
  3485.                                      var H : boolean);
  3486.   var
  3487.     ColData : TOvcTableColumn;
  3488.   begin
  3489.     ColData := FCols[ColNum];
  3490.     if Assigned(ColData) then with ColData do
  3491.       begin
  3492.         W := Width;
  3493.         if (DefaultCell <> nil) then
  3494.           A := DefaultCell.Access
  3495.         else
  3496.           A := otxReadOnly;
  3497.         H := Hidden;
  3498.       end;
  3499.   end;
  3500. {--------}
  3501. procedure TOvcCustomTable.tbQueryRowData(RowNum : TRowNum;
  3502.                                      var Ht: integer;
  3503.                                      var H : boolean);
  3504.   var
  3505.     RowData : TRowStyle;
  3506.   begin
  3507.     RowData := FRows[RowNum];
  3508.     with RowData do
  3509.       begin
  3510.         Ht:= Height;
  3511.         H := Hidden;
  3512.       end;
  3513.   end;
  3514. {--------}
  3515. procedure TOvcCustomTable.SetBounds(ALeft, ATop, AWidth, AHeight: integer);
  3516.   var
  3517.     WidthChanged  : boolean;
  3518.     HeightChanged : boolean;
  3519.   begin
  3520.     if (not HandleAllocated) then
  3521.       begin
  3522.         inherited SetBounds(ALeft, ATop, AWidth, AHeight);
  3523.         Exit;
  3524.       end;
  3525.  
  3526.     WidthChanged := (Width <> AWidth);
  3527.     HeightChanged := (Height <> AHeight);
  3528.  
  3529.     if WidthChanged or HeightChanged then
  3530.       begin
  3531.         AllowRedraw := false;
  3532.         try
  3533.           inherited SetBounds(ALeft, ATop, AWidth, AHeight);
  3534.           if WidthChanged then
  3535.             tbCalcColData(tbColNums, LeftCol);
  3536.           if HeightChanged then
  3537.             tbCalcRowData(tbRowNums, TopRow);
  3538.           tbSetScrollRange(otsbVertical);
  3539.           tbSetScrollRange(otsbHorizontal);
  3540.           if (TopRow > tbLastTopRow) then
  3541.             TopRow := tbLastTopRow;
  3542.           if (LeftCol > tbLastLeftCol) then
  3543.             LeftCol := tbLastLeftCol;
  3544.           InvalidateTable;
  3545.         finally
  3546.           AllowRedraw := true;
  3547.         end;{try..finally}
  3548.       end
  3549.     else
  3550.       inherited SetBounds(ALeft, ATop, AWidth, AHeight);
  3551.   end;
  3552. {====================================================================}
  3553.  
  3554.  
  3555. {==TOvcTable active cell movement====================================}
  3556. procedure TOvcCustomTable.tbMoveActCellBotOfPage;
  3557.   var
  3558.     RowInx : integer;
  3559.     NewActiveRow : TRowNum;
  3560.     NewActiveCol : TColNum;
  3561.   begin
  3562.     with tbRowNums^ do
  3563.       if (Ay[Count].Offset <= ClientHeight) then
  3564.         NewActiveRow := IncRow(Ay[pred(Count)].Number, 0)
  3565.       else
  3566.         begin
  3567.           RowInx := pred(Count);
  3568.           if (RowInx > 0) then
  3569.             dec(RowInx);
  3570.           if (Ay[RowInx].Number < LockedRows) then
  3571.             NewActiveRow := IncRow(TopRow, 0)
  3572.           else
  3573.             NewActiveRow := IncRow(Ay[RowInx].Number, 0);
  3574.         end;
  3575.     NewActiveCol := ActiveCol;
  3576.     DoActiveCellMoving(ccBotOfPage, NewActiveRow, NewActiveCol);
  3577.     if (ActiveRow <> NewActiveRow) or (ActiveCol <> NewActiveCol) then
  3578.       begin
  3579.         tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3580.       end;
  3581.   end;
  3582. {--------}
  3583. procedure TOvcCustomTable.tbMoveActCellBotRight;
  3584.   var
  3585.     NewActiveRow : TRowNum;
  3586.     NewActiveCol : TColNum;
  3587.   begin
  3588.     NewActiveRow := IncRow(pred(RowLimit), 0);
  3589.     NewActiveCol := IncCol(pred(ColCount), 0);
  3590.     DoActiveCellMoving(ccBotRightCell, NewActiveRow, NewActiveCol);
  3591.     if (ActiveRow <> NewActiveRow) or (ActiveCol <> NewActiveCol) then
  3592.       begin
  3593.         tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3594.       end;
  3595.   end;
  3596. {--------}
  3597. procedure TOvcCustomTable.tbMoveActCellDown;
  3598.   var
  3599.     NewTopRow    : TRowNum;
  3600.     NewActiveRow : TRowNum;
  3601.     NewActiveCol : TColNum;
  3602.     i            : integer;
  3603.   begin
  3604.     NewTopRow := TopRow;
  3605.     NewActiveRow := IncRow(ActiveRow, 1);
  3606.     NewActiveCol := ActiveCol;
  3607.     DoActiveCellMoving(ccDown, NewActiveRow, NewActiveCol);
  3608.     if (ActiveRow <> NewActiveRow) or (ActiveCol <> NewActiveCol) then
  3609.       begin
  3610.         {we need to take care of a special case: if the current active
  3611.          cell is *exactly* on the last row of the page, we need to
  3612.          artificially move the top row down by one, before setting the
  3613.          active cell, otherwise the top row is forced to the active cell
  3614.          later on--a bit disconcerting.}
  3615.         with tbRowNums^ do
  3616.           if (Ay[Count].Offset = ClientHeight) and
  3617.              (ActiveRow = Ay[pred(Count)].Number) and
  3618.              (NewActiveRow > ActiveRow) then
  3619.             begin
  3620.               for i := 1 to NewActiveRow-ActiveRow do
  3621.                 NewTopRow := IncRow(TopRow, 1);
  3622.               if (NewTopRow < NewActiveRow) then
  3623.                 begin
  3624.                   AllowRedraw := False;
  3625.                   try
  3626.                     TopRow := NewTopRow;
  3627.                     tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3628.                   finally
  3629.                     AllowRedraw := True;
  3630.                   end;{try..finally}
  3631.                 end
  3632.               else
  3633.                 tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3634.             end
  3635.           else
  3636.             begin
  3637.               tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3638.             end;
  3639.       end;
  3640.   end;
  3641. {--------}
  3642. procedure TOvcCustomTable.tbMoveActCellFirstCol;
  3643.   var
  3644.     NewActiveRow : TRowNum;
  3645.     NewActiveCol : TColNum;
  3646.   begin
  3647.     NewActiveCol := IncCol(LockedCols, 0);
  3648.     NewActiveRow := ActiveRow;
  3649.     DoActiveCellMoving(ccHome, NewActiveRow, NewActiveCol);
  3650.     if (ActiveCol <> NewActiveCol) or (ActiveRow <> NewActiveRow) then
  3651.       begin
  3652.         tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3653.       end;
  3654.   end;
  3655. {--------}
  3656. procedure TOvcCustomTable.tbMoveActCellFirstRow;
  3657.   var
  3658.     NewActiveRow : TRowNum;
  3659.     NewActiveCol : TColNum;
  3660.   begin
  3661.     NewActiveRow := IncRow(LockedRows, 0);
  3662.     NewActiveCol := ActiveCol;
  3663.     DoActiveCellMoving(ccFirstPage, NewActiveRow, NewActiveCol);
  3664.     if (ActiveRow <> NewActiveRow) then
  3665.       begin
  3666.         tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3667.       end;
  3668.   end;
  3669. {--------}
  3670. procedure TOvcCustomTable.tbMoveActCellLastCol;
  3671.   var
  3672.     NewActiveRow : TRowNum;
  3673.     NewActiveCol : TColNum;
  3674.   begin
  3675.     NewActiveCol := IncCol(pred(ColCount), 0);
  3676.     NewActiveRow := ActiveRow;
  3677.     DoActiveCellMoving(ccEnd, NewActiveRow, NewActiveCol);
  3678.     if (ActiveCol <> NewActiveCol) or (ActiveRow <> NewActiveRow) then
  3679.       begin
  3680.         tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3681.       end;
  3682.   end;
  3683. {--------}
  3684. procedure TOvcCustomTable.tbMoveActCellLastRow;
  3685.   var
  3686.     NewActiveRow : TRowNum;
  3687.     NewActiveCol : TColNum;
  3688.   begin
  3689.     NewActiveRow := IncRow(pred(RowLimit), 0);
  3690.     if (ActiveRow <> NewActiveRow) or (ActiveCol <> NewActiveCol) then
  3691.       begin
  3692.         NewActiveCol := ActiveCol;
  3693.         DoActiveCellMoving(ccLastPage, NewActiveRow, NewActiveCol);
  3694.         tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3695.       end;
  3696.   end;
  3697. {--------}
  3698. procedure TOvcCustomTable.tbMoveActCellLeft;
  3699.   var
  3700.     NewActiveRow : TRowNum;
  3701.     NewActiveCol : TColNum;
  3702.   begin
  3703.     NewActiveCol := IncCol(ActiveCol, -1);
  3704.     NewActiveRow := ActiveRow;
  3705.     DoActiveCellMoving(ccLeft, NewActiveRow, NewActiveCol);
  3706.     if (ActiveCol <> NewActiveCol) or (ActiveRow <> NewActiveRow) then
  3707.       begin
  3708.         tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3709.       end;
  3710.   end;
  3711. {--------}
  3712. procedure TOvcCustomTable.tbMoveActCellPageDown;
  3713.   var
  3714.     NewTopRow,
  3715.     CurRow, LastRow : TRowNum;
  3716.     CurInx, LastInx : integer;
  3717.     NewActiveRow : TRowNum;
  3718.     NewActiveCol : TColNum;
  3719.   begin
  3720.     CurRow := ActiveRow;
  3721.     CurInx := tbFindRowInx(CurRow);
  3722.     with tbRowNums^ do
  3723.       begin
  3724.         LastInx := pred(Count);
  3725.         LastRow := Ay[LastInx].Number;
  3726.       end;
  3727.     if (CurRow = LastRow) then
  3728.       NewTopRow := IncRow(LastRow, 1)
  3729.     else
  3730.       NewTopRow := LastRow;
  3731.  
  3732.     AllowRedraw := false;
  3733.     try
  3734.       TopRow := NewTopRow;
  3735.  
  3736.       if (CurInx = -1) then
  3737.         NewActiveRow := IncRow(TopRow, 0)
  3738.       else if (CurInx < tbRowNums^.Count) then
  3739.         NewActiveRow := IncRow(tbRowNums^.Ay[CurInx].Number, 0)
  3740.       else
  3741.         NewActiveRow := IncRow(tbRowNums^.Ay[pred(tbRowNums^.Count)].Number, 0);
  3742.       NewActiveCol := ActiveCol;
  3743.       DoActiveCellMoving(ccNextPage, NewActiveRow, NewActiveCol);
  3744.       if (ActiveRow <> NewActiveRow) or (ActiveCol <> NewActiveCol) then
  3745.         begin
  3746.           tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3747.         end;
  3748.     finally
  3749.       AllowRedraw := true;
  3750.     end;{try..finally}
  3751.   end;
  3752. {--------}
  3753. procedure TOvcCustomTable.tbMoveActCellPageLeft;
  3754.   var
  3755.     Walker,
  3756.     CurLeftCol : TRowNum;
  3757.     CurInx : integer;
  3758.     NewActiveRow : TRowNum;
  3759.     NewActiveCol : TColNum;
  3760.   begin
  3761.     CurLeftCol := LeftCol;
  3762.     if (ActiveCol = LeftCol) then
  3763.       begin
  3764.         Walker := IncCol(CurLeftCol, -1);
  3765.         if (Walker = CurLeftCol) then
  3766.           Exit;
  3767.       end;
  3768.     CurInx := tbFindColInx(ActiveCol);
  3769.     AllowRedraw := false;
  3770.     try
  3771.       tbScrollBarPageLeft;
  3772.       if (CurInx = -1) or (CurLeftCol = LeftCol) then
  3773.         NewActiveCol := IncCol(LeftCol, 0)
  3774.       else if (CurInx < tbColNums^.Count) then
  3775.         NewActiveCol := IncCol(tbColNums^.Ay[CurInx].Number, 0)
  3776.       else
  3777.         NewActiveCol := IncCol(tbColNums^.Ay[pred(tbColNums^.Count)].Number, 0);
  3778.       NewActiveRow := ActiveRow;
  3779.       DoActiveCellMoving(ccPageLeft, NewActiveRow, NewActiveCol);
  3780.       if (ActiveCol <> NewActiveCol) or (ActiveRow <> NewActiveRow) then
  3781.         begin
  3782.           tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3783.         end;
  3784.     finally
  3785.       AllowRedraw := true;
  3786.     end;{try..finally}
  3787.   end;
  3788. {--------}
  3789. procedure TOvcCustomTable.tbMoveActCellPageRight;
  3790.   var
  3791.     NewLeftCol,
  3792.     CurCol, LastCol : TColNum;
  3793.     CurInx, LastInx : integer;
  3794.     NewActiveRow : TRowNum;
  3795.     NewActiveCol : TColNum;
  3796.   begin
  3797.     CurCol := ActiveCol;
  3798.     CurInx := tbFindColInx(CurCol);
  3799.     with tbColNums^ do
  3800.       begin
  3801.         LastInx := pred(Count);
  3802.         LastCol := Ay[LastInx].Number;
  3803.       end;
  3804.     if (CurCol = LastCol) then
  3805.       NewLeftCol := IncCol(LastCol, 1)
  3806.     else
  3807.       NewLeftCol := LastCol;
  3808.  
  3809.     AllowRedraw := false;
  3810.     try
  3811.       LeftCol := NewLeftCol;
  3812.  
  3813.       if (CurInx = -1) then
  3814.         NewActiveCol := IncCol(LeftCol, 0)
  3815.       else if (CurInx < tbColNums^.Count) then
  3816.         NewActiveCol := IncCol(tbColNums^.Ay[CurInx].Number, 0)
  3817.       else
  3818.         NewActiveCol := IncCol(tbColNums^.Ay[pred(tbColNums^.Count)].Number, 0);
  3819.       NewActiveRow := ActiveRow;
  3820.       DoActiveCellMoving(ccPageRight, NewActiveRow, NewActiveCol);
  3821.       if (ActiveCol <> NewActiveCol) or (ActiveRow <> NewActiveRow) then
  3822.         begin
  3823.           tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3824.         end;
  3825.     finally
  3826.       AllowRedraw := true;
  3827.     end;{try..finally}
  3828.   end;
  3829. {--------}
  3830. procedure TOvcCustomTable.tbMoveActCellPageUp;
  3831.   var
  3832.     Walker,
  3833.     CurTopRow : TRowNum;
  3834.     CurInx : integer;
  3835.     NewActiveRow : TRowNum;
  3836.     NewActiveCol : TColNum;
  3837.   begin
  3838.     CurTopRow := TopRow;
  3839.     if (ActiveRow = TopRow) then
  3840.       begin
  3841.         Walker := IncRow(CurTopRow, -1);
  3842.         if (Walker = CurTopRow) then
  3843.           Exit;
  3844.       end;
  3845.     CurInx := tbFindRowInx(ActiveRow);
  3846.     AllowRedraw := false;
  3847.     try
  3848.       tbScrollBarPageUp;
  3849.       if (CurInx = -1) or (CurTopRow = TopRow) then
  3850.         NewActiveRow := IncRow(TopRow, 0)
  3851.       else if (CurInx < tbRowNums^.Count) then
  3852.         NewActiveRow := IncRow(tbRowNums^.Ay[CurInx].Number, 0)
  3853.       else
  3854.         NewActiveRow := IncRow(tbRowNums^.Ay[pred(tbRowNums^.Count)].Number, 0);
  3855.       NewActiveCol := ActiveCol;
  3856.       DoActiveCellMoving(ccPrevPage, NewActiveRow, NewActiveCol);
  3857.       if (ActiveRow <> NewActiveRow) or (ActiveCol <> NewActiveCol) then
  3858.         begin
  3859.           tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3860.         end;
  3861.     finally
  3862.       AllowRedraw := true;
  3863.     end;{try..finally}
  3864.   end;
  3865. {--------}
  3866. procedure TOvcCustomTable.tbMoveActCellRight;
  3867.   var
  3868.     NewActiveRow : TRowNum;
  3869.     NewLeftCol,
  3870.     NewActiveCol : TColNum;
  3871.     i            : integer;
  3872.   begin
  3873.     NewLeftCol := LeftCol;
  3874.     NewActiveCol := IncCol(ActiveCol, 1);
  3875.     NewActiveRow := ActiveRow;
  3876.     DoActiveCellMoving(ccRight, NewActiveRow, NewActiveCol);
  3877.     if (ActiveCol <> NewActiveCol) or (ActiveRow <> NewActiveRow) then
  3878.       begin
  3879.         {we need to take care of a special case: if the current active
  3880.          cell is *exactly* on the last column of the page, we need to
  3881.          artificially move the leftmost column across by one, before
  3882.          setting the active cell, otherwise the leftmost column is
  3883.          forced to the active cell later on--a bit disconcerting.}
  3884.         with tbColNums^ do
  3885.           if (NewActiveCol > ActiveCol) and
  3886.              (ActiveCol = Ay[pred(Count)].Number) and
  3887.              (Ay[Count].Offset = ClientWidth) then
  3888.             begin
  3889.               for i := 1 to NewActiveCol-ActiveCol do
  3890.                 NewLeftCol := IncCol(LeftCol, 1);
  3891.               if (NewLeftCol < NewActiveCol) then
  3892.                 begin
  3893.                   AllowRedraw := False;
  3894.                   try
  3895.                     LeftCol := NewLeftCol;
  3896.                     tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3897.                   finally
  3898.                     AllowRedraw := True;
  3899.                   end;{try..finally}
  3900.                 end
  3901.               else
  3902.                 tbSetActiveCellWithSel(NewActiveRow, NewActiveCol)
  3903.             end
  3904.           else
  3905.             tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3906.       end;
  3907.   end;
  3908. {--------}
  3909. procedure TOvcCustomTable.tbMoveActCellTopLeft;
  3910.   var
  3911.     NewActiveRow : TRowNum;
  3912.     NewActiveCol : TColNum;
  3913.   begin
  3914.     NewActiveRow := IncRow(LockedRows, 0);
  3915.     NewActiveCol := IncCol(LockedCols, 0);
  3916.     DoActiveCellMoving(ccTopLeftCell, NewActiveRow, NewActiveCol);
  3917.     if (ActiveRow <> NewActiveRow) or (ActiveCol <> NewActiveCol) then
  3918.       begin
  3919.         tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3920.       end;
  3921.   end;
  3922. {--------}
  3923. procedure TOvcCustomTable.tbMoveActCellTopOfPage;
  3924.   var
  3925.     NewActiveRow : TRowNum;
  3926.     NewActiveCol : TColNum;
  3927.   begin
  3928.     NewActiveRow := IncRow(TopRow, 0);
  3929.     NewActiveCol := ActiveCol;
  3930.     DoActiveCellMoving(ccTopOfPage, NewActiveRow, NewActiveCol);
  3931.     if (ActiveRow <> NewActiveRow) or (ActiveCol <> NewActiveCol) then
  3932.       begin
  3933.         tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3934.       end;
  3935.   end;
  3936. {--------}
  3937. procedure TOvcCustomTable.tbMoveActCellUp;
  3938.   var
  3939.     NewActiveRow : TRowNum;
  3940.     NewActiveCol : TColNum;
  3941.   begin
  3942.     NewActiveRow := IncRow(ActiveRow, -1);
  3943.     NewActiveCol := ActiveCol;
  3944.     DoActiveCellMoving(ccUp, NewActiveRow, NewActiveCol);
  3945.     if (ActiveRow <> NewActiveRow) or (ActiveCol <> NewActiveCol) then
  3946.       begin
  3947.         tbSetActiveCellWithSel(NewActiveRow, NewActiveCol);
  3948.       end;
  3949.   end;
  3950. {--------}
  3951. procedure TOvcCustomTable.MoveActiveCell(Command : word);
  3952.   begin
  3953.     if (otoNoSelection in Options) then
  3954.       tbIsKeySelecting := false;
  3955.  
  3956.     case Command of
  3957.       {NOTE: this case statement has been optimised, the ccXxx
  3958.        constants are in ASCENDING order of value not name--it's
  3959.        lucky that the former implies the latter.}
  3960.       ccBotOfPage     : tbMoveActCellBotOfPage;
  3961.       ccBotRightCell  : tbMoveActCellBotRight;
  3962.       ccDown          : tbMoveActCellDown;
  3963.       ccEnd           : tbMoveActCellLastCol;
  3964.       ccFirstPage     : tbMoveActCellFirstRow;
  3965.       ccHome          : tbMoveActCellFirstCol;
  3966.       ccLastPage      : tbMoveActCellLastRow;
  3967.       ccLeft          : tbMoveActCellLeft;
  3968.       ccNextPage      : tbMoveActCellPageDown;
  3969.       ccPageLeft      : tbMoveActCellPageLeft;
  3970.       ccPageRight     : tbMoveActCellPageRight;
  3971.       ccPrevPage      : tbMoveActCellPageUp;
  3972.       ccRight         : tbMoveActCellRight;
  3973.       ccTopLeftCell   : tbMoveActCellTopLeft;
  3974.       ccTopOfPage     : tbMoveActCellTopOfPage;
  3975.       ccUp            : tbMoveActCellUp;
  3976.     end;{case}
  3977.   end;
  3978. {====================================================================}
  3979.  
  3980.  
  3981. {==TOvcTable scrollbar event handlers================================}
  3982. procedure TOvcCustomTable.ProcessScrollBarClick(ScrollBar : TOvcScrollBar;
  3983.                                                 ScrollCode : TScrollCode);
  3984.   var
  3985.     Form : TForm;
  3986.   begin
  3987.     {check to see whether the cell being edited is valid;
  3988.      no scrolling allowed if it isn't (tough).}
  3989.     if InEditingState then
  3990.       begin
  3991.         if not tbActCell.CanSaveEditedData(true) then
  3992.           Exit;
  3993.       end;
  3994.     {perform the scroll}
  3995.     if (ScrollBar = otsbVertical) then
  3996.       case ScrollCode of
  3997.         scLineUp   : tbScrollBarUp;
  3998.         scLineDown : tbScrollBarDown;
  3999.         scPageUp   : tbScrollBarPageUp;
  4000.         scPageDown : tbScrollBarPageDown;
  4001.       end{case}
  4002.     else {it's otsbHorizontal}
  4003.       case ScrollCode of
  4004.         scLineUp   : tbScrollBarLeft;
  4005.         scLineDown : tbScrollBarRight;
  4006.         scPageUp   : tbScrollBarPageLeft;
  4007.         scPageDown : tbScrollBarPageRight;
  4008.       end;{case}
  4009.     if (otsDesigning in tbState) then
  4010.       begin
  4011.         Form := TForm(GetParentForm(Self));
  4012.         if (Form <> nil) and (Form.Designer <> nil) then
  4013.           Form.Designer.Modified;
  4014.       end;
  4015.   end;
  4016. {--------}
  4017. procedure TOvcCustomTable.tbScrollBarDown;
  4018.   begin
  4019.     TopRow := IncRow(TopRow, 1);
  4020.   end;
  4021. {--------}
  4022. procedure TOvcCustomTable.tbScrollBarPageDown;
  4023.   var
  4024.     LastInx : integer;
  4025.     LastRow : TRowNum;
  4026.   begin
  4027.     with tbRowNums^ do
  4028.       begin
  4029.         LastInx := pred(Count);
  4030.         LastRow := Ay[LastInx].Number;
  4031.       end;
  4032.     if (TopRow <> LastRow) then
  4033.       TopRow := LastRow
  4034.     else
  4035.       TopRow := IncRow(TopRow, 1);
  4036.   end;
  4037. {--------}
  4038. procedure TOvcCustomTable.tbScrollBarPageUp;
  4039.   var
  4040.     CurTopRow : TRowNum;
  4041.     Walker    : TRowNum;
  4042.     CH        : integer;
  4043.     OurRowNums: POvcTblDisplayArray;
  4044.     NewTopRow : TRowNum;
  4045.   begin
  4046.     {-Scroll the table so that the current top row appears at
  4047.       the bottom of the table window (if possible).}
  4048.     CurTopRow := TopRow;
  4049.     Walker := IncRow(CurTopRow, -1);
  4050.     if (Walker = CurTopRow) then
  4051.       Exit;
  4052.  
  4053.     OurRowNums := nil;
  4054.     AssignDisplayArray(OurRowNums, tbRowNums^.AllocNm);
  4055.     try
  4056.       CH := ClientHeight;
  4057.       NewTopRow := Walker;
  4058.       tbCalcRowData(OurRowNums, NewTopRow);
  4059.       while (OurRowNums^.Ay[OurRowNums^.Count].Offset < CH) or
  4060.             (OurRowNums^.Ay[pred(OurRowNums^.Count)].Number > CurTopRow) do
  4061.       begin
  4062.         Walker := IncRow(NewTopRow, -1);
  4063.         if (Walker = NewTopRow) then
  4064.           Break;
  4065.         NewTopRow := Walker;
  4066.         tbCalcRowData(OurRowNums, NewTopRow);
  4067.       end;
  4068.     finally
  4069.       AssignDisplayArray(OurRowNums, 0);
  4070.     end;{try..finally}
  4071.     TopRow := NewTopRow;
  4072.   end;
  4073. {--------}
  4074. procedure TOvcCustomTable.tbScrollBarUp;
  4075.   begin
  4076.     TopRow := IncRow(TopRow, -1);
  4077.   end;
  4078. {--------}
  4079. procedure TOvcCustomTable.tbScrollBarLeft;
  4080.   begin
  4081.     LeftCol := IncCol(LeftCol, -1);
  4082.   end;
  4083. {--------}
  4084. procedure TOvcCustomTable.tbScrollBarPageLeft;
  4085.   var
  4086.     CurLeftCol : TColNum;
  4087.     Walker     : TColNum;
  4088.     CW         : integer;
  4089.     OurColNums : POvcTblDisplayArray;
  4090.     NewLeftCol : TColNum;
  4091.   begin
  4092.     CurLeftCol := LeftCol;
  4093.     Walker := IncCol(CurLeftCol, -1);
  4094.     if (Walker = CurLeftCol) then
  4095.       Exit;
  4096.  
  4097.     OurColNums := nil;
  4098.     AssignDisplayArray(OurColNums, tbColNums^.AllocNm);
  4099.     try
  4100.       CW := ClientWidth;
  4101.       NewLeftCol := Walker;
  4102.       tbCalcColData(OurColNums, NewLeftCol);
  4103.       while (OurColNums^.Ay[OurColNums^.Count].Offset < CW) or
  4104.             (OurColNums^.Ay[pred(OurColNums^.Count)].Number > CurLeftCol) do
  4105.       begin
  4106.         Walker := IncCol(NewLeftCol, -1);
  4107.         if (Walker = NewLeftCol) then
  4108.           Break;
  4109.         NewLeftCol := Walker;
  4110.         tbCalcColData(OurColNums, NewLeftCol);
  4111.       end;
  4112.     finally
  4113.       AssignDisplayArray(OurColNums, 0);
  4114.     end;{try..finally}
  4115.     LeftCol := NewLeftCol;
  4116.   end;
  4117. {--------}
  4118. procedure TOvcCustomTable.tbScrollBarPageRight;
  4119.   var
  4120.     LastInx : integer;
  4121.     LastCol : TColNum;
  4122.   begin
  4123.     with tbColNums^ do
  4124.       begin
  4125.         LastInx := pred(Count);
  4126.         LastCol := Ay[LastInx].Number;
  4127.       end;
  4128.     if (LeftCol <> LastCol) then
  4129.       LeftCol := LastCol
  4130.     else
  4131.       LeftCol := IncCol(LeftCol, 1);
  4132.   end;
  4133. {--------}
  4134. procedure TOvcCustomTable.tbScrollBarRight;
  4135.   begin
  4136.     LeftCol := IncCol(LeftCol, 1);
  4137.   end;
  4138. {====================================================================}
  4139.  
  4140.  
  4141. {==TOvcTable table scrolling routines================================}
  4142. procedure TOvcCustomTable.tbScrollTableLeft(NewLeftCol : TColNum);
  4143.   var
  4144.     NewColInx : integer;
  4145.     NewCLOfs  : integer;
  4146.     OldColRight : TColNum;
  4147.     OldColInx : integer;
  4148.     OldCLOfs  : integer;
  4149.     ColNum    : TColNum;
  4150.     R         : TRect;
  4151.     CW        : integer;
  4152.   begin
  4153.     {the window is scrolled left, ie the new leftmost column
  4154.      is to the right of the current leftmost column}
  4155.     AllowRedraw := false;
  4156.     try
  4157.       NewColInx := tbFindColInx(NewLeftCol);
  4158.       CW := ClientWidth;
  4159.       if (NewColInx = -1) or
  4160.          (tbColNums^.Ay[succ(NewColInx)].Offset > CW) then
  4161.         begin
  4162.           {the new leftmost column is not (fully) visible}
  4163.           FLeftCol := NewLeftCol;
  4164.           tbCalcColData(tbColNums, LeftCol);
  4165.           InvalidateTableNotLockedCols;
  4166.         end
  4167.       else
  4168.         begin
  4169.           {the new leftmost column is fully visible}
  4170.           OldColInx := tbFindColInx(FLeftCol);
  4171.           with tbColNums^ do
  4172.             begin
  4173.               OldColRight := Ay[pred(Count)].Number;
  4174.               if (Ay[Count].Offset < CW) then
  4175.                 begin
  4176.                   inc(OldColRight);
  4177.                   tbInvCells.AddUnusedBit;
  4178.                 end;
  4179.               NewCLOfs := Ay[NewColInx].Offset;
  4180.               OldCLOfs := Ay[OldColInx].Offset;
  4181.             end;
  4182.           R := Rect(OldCLOfs, 0, CW, ClientHeight);
  4183.           ScrollWindow(Handle,
  4184.                        (OldCLOfs-NewCLOfs), 0,
  4185.                        @R, @R);
  4186.           FLeftCol := NewLeftCol;
  4187.           tbCalcColData(tbColNums, LeftCol);
  4188.           if (OldColRight <= tbColNums^.Ay[pred(tbColNums^.Count)].Number) then
  4189.             begin
  4190.               tbInvCells.AddUnusedBit;
  4191.               for ColNum := OldColRight to tbColNums^.Ay[pred(tbColNums^.Count)].Number do
  4192.                 InvalidateColumn(ColNum);
  4193.             end;
  4194.           R.Left := OldCLOfs + (CW - NewCLOfs);
  4195.           ValidateRect(Handle, @R);
  4196.           tbMustUpdate := true;
  4197.           UpdateWindow(Handle);
  4198.         end;
  4199.     finally
  4200.       AllowRedraw := true;
  4201.     end;{try..finally}
  4202.   end;
  4203. {--------}
  4204. procedure TOvcCustomTable.tbScrollTableRight(NewLeftCol : TColNum);
  4205.   var
  4206.     OldLeftCol: TColNum;
  4207.     OldColInx : integer;
  4208.     OldCLOfs  : integer;
  4209.     OrigOfs   : integer;
  4210.     ColNum    : TColNum;
  4211.     R         : TRect;
  4212.   begin
  4213.     {the window is scrolled right, ie the new leftmost column
  4214.      is to the left of the current leftmost column}
  4215.     AllowRedraw := false;
  4216.     try
  4217.       OldLeftCol := FLeftCol;
  4218.       OldColInx := tbFindColInx(OldLeftCol);
  4219.       OrigOfs := tbColNums^.Ay[OldColInx].Offset;
  4220.       FLeftCol := NewLeftCol;
  4221.       tbCalcColData(tbColNums, LeftCol);
  4222.       OldColInx := tbFindColInx(OldLeftCol);
  4223.       if (OldColInx = -1) then
  4224.         begin
  4225.           {the old leftmost column is no longer visible}
  4226.           InvalidateTableNotLockedCols;
  4227.         end
  4228.       else
  4229.         begin
  4230.           {the old leftmost column is (partially) visible}
  4231.           OldCLOfs := tbColNums^.Ay[OldColInx].Offset;
  4232.           R := Rect(OrigOfs, 0, ClientWidth, ClientHeight);
  4233.           ScrollWindow(Handle,
  4234.                        (OldClOfs-OrigOfs), 0,
  4235.                        @R, @R);
  4236.           for ColNum := FLeftCol to pred(OldLeftCol) do
  4237.             InvalidateColumn(ColNum);
  4238.           R.Right := OldCLOfs;
  4239.           ValidateRect(Handle, @R);
  4240.           tbMustUpdate := true;
  4241.           UpdateWindow(Handle);
  4242.         end;
  4243.     finally
  4244.       AllowRedraw := true;
  4245.     end;{try..finally}
  4246.   end;
  4247. {--------}
  4248. procedure TOvcCustomTable.tbScrollTableUp(NewTopRow : TRowNum);
  4249.   var
  4250.     NewRowInx : integer;
  4251.     NewRTOfs  : integer;
  4252.     OldRowBottom : TRowNum;
  4253.     OldRowInx : integer;
  4254.     OldRTOfs  : integer;
  4255.     RowNum    : TRowNum;
  4256.     R         : TRect;
  4257.     CH        : integer;
  4258.   begin
  4259.     {the window is scrolled up, ie the new topmost row
  4260.      is underneath the current topmost row}
  4261.     AllowRedraw := false;
  4262.     try
  4263.       NewRowInx := tbFindRowInx(NewTopRow);
  4264.       CH := ClientHeight;
  4265.       if (NewRowInx = -1) or
  4266.          (tbRowNums^.Ay[succ(NewRowInx)].Offset > CH) then
  4267.         begin
  4268.           {the new topmost row is not (fully) visible}
  4269.           FTopRow := NewTopRow;
  4270.           tbCalcRowData(tbRowNums, TopRow);
  4271.           InvalidateTableNotLockedRows;
  4272.         end
  4273.       else
  4274.         begin
  4275.           {the new topmost row is fully visible}
  4276.           OldRowInx := tbFindRowInx(FTopRow);
  4277.           with tbRowNums^ do
  4278.             begin
  4279.               OldRowBottom := Ay[pred(Count)].Number;
  4280.               if (Ay[Count].Offset < CH) then
  4281.                 begin
  4282.                   inc(OldRowBottom);
  4283.                   tbInvCells.AddUnusedBit;
  4284.                 end;
  4285.               NewRTOfs := Ay[NewRowInx].Offset;
  4286.               OldRTOfs := Ay[OldRowInx].Offset;
  4287.             end;
  4288.           R := Rect(0, OldRTOfs, ClientWidth, CH);
  4289.           ScrollWindow(Handle,
  4290.                        0, (OldRTOfs-NewRTOfs),
  4291.                        @R, @R);
  4292.           FTopRow := NewTopRow;
  4293.           tbCalcRowData(tbRowNums, TopRow);
  4294.           if (OldRowBottom <= tbRowNums^.Ay[pred(tbRowNums^.Count)].Number) then
  4295.             begin
  4296.               tbInvCells.AddUnusedBit;
  4297.               for RowNum := OldRowBottom to tbRowNums^.Ay[pred(tbRowNums^.Count)].Number do
  4298.                 InvalidateRow(RowNum);
  4299.             end;
  4300.           R.Top := OldRTOfs + (CH - NewRTOfs);
  4301.           ValidateRect(Handle, @R);
  4302.           tbMustUpdate := true;
  4303.           UpdateWindow(Handle);
  4304.         end;
  4305.     finally
  4306.       AllowRedraw := true;
  4307.     end;{try..finally}
  4308.   end;
  4309. {--------}
  4310. procedure TOvcCustomTable.tbScrollTableDown(NewTopRow : TRowNum);
  4311.   var
  4312.     OldTopRow : TRowNum;
  4313.     OldRowInx : integer;
  4314.     OldRTOfs  : integer;
  4315.     OrigOfs   : integer;
  4316.     RowNum    : TRowNum;
  4317.     R         : TRect;
  4318.   begin
  4319.     {the window is scrolled down, ie the new topmost row
  4320.      is above the current topmost row}
  4321.     AllowRedraw := false;
  4322.     try
  4323.       OldTopRow := FTopRow;
  4324.       OldRowInx := tbFindRowInx(OldTopRow);
  4325.       OrigOfs := tbRowNums^.Ay[OldRowInx].Offset;
  4326.       FTopRow := NewTopRow;
  4327.       tbCalcRowData(tbRowNums, TopRow);
  4328.       OldRowInx := tbFindRowInx(OldTopRow);
  4329.       if (OldRowInx = -1) then
  4330.         begin
  4331.           {the old topmost row is no longer visible}
  4332.           InvalidateTableNotLockedRows;
  4333.         end
  4334.       else
  4335.         begin
  4336.           {the old topmost row is (partially) visible}
  4337.           OldRTOfs := tbRowNums^.Ay[OldRowInx].Offset;
  4338.           R := Rect(0, OrigOfs, ClientWidth, ClientHeight);
  4339.           ScrollWindow(Handle,
  4340.                        0, (OldRTOfs-OrigOfs),
  4341.                        @R, @R);
  4342.           for RowNum := FTopRow to pred(OldTopRow) do
  4343.             InvalidateRow(RowNum);
  4344.           R.Bottom := OldRTOfs;
  4345.           ValidateRect(Handle, @R);
  4346.           tbMustUpdate := true;
  4347.           UpdateWindow(Handle);
  4348.         end;
  4349.     finally
  4350.       AllowRedraw := true;
  4351.     end;{try..finally}
  4352.   end;
  4353. {====================================================================}
  4354.  
  4355.  
  4356. {==TOvcTable drawing routines========================================}
  4357. procedure TOvcCustomTable.tbDrawActiveCell;
  4358.   var
  4359.     RowOfs : integer;
  4360.     ColOfs : integer;
  4361.     RowInx : integer;
  4362.     ColInx : integer;
  4363.     Ht     : integer;
  4364.     Wd     : integer;
  4365.     ActRowOfs    : integer;
  4366.     ActRowBottom : integer;
  4367.     ActColOfs    : integer;
  4368.     ActColRight  : integer;
  4369.     GridPen      : TOvcGridPen;
  4370.     BrushColor   : TColor;
  4371.     DrawItFocused: boolean;
  4372.   begin
  4373.     ActRowOfs    := 0;
  4374.     ActRowBottom := 0;
  4375.     ActColOfs    := 0;
  4376.     ActColRight  := 0;
  4377.  
  4378.     {Find the cell's row on the screen, exit if not present}
  4379.     RowInx := tbFindRowInx(ActiveRow);
  4380.     if (RowInx = -1) then Exit;
  4381.  
  4382.     {Find the cell's column on the screen, exit if not present}
  4383.     ColInx := tbFindColInx(ActiveCol);
  4384.     if (ColInx = -1) then Exit;
  4385.  
  4386.     {If we are in editing mode, display the editing control for the
  4387.      cell, otherwise, draw the focus box around the cell contents}
  4388.     if InEditingState then
  4389.       begin
  4390.         UpdateWindow(tbActCell.EditHandle);
  4391.       end
  4392.     else
  4393.       begin
  4394.         {draw the box round the cell}
  4395.         with Canvas do
  4396.           begin
  4397.             {get the correct grid pen}
  4398.             if (otsFocused in tbState) then
  4399.               begin
  4400.                 GridPen := GridPenSet.CellWhenFocused;
  4401.                 DrawItFocused := true;
  4402.               end
  4403.             else
  4404.               begin
  4405.                 GridPen := GridPenSet.CellWhenUnfocused;
  4406.                 DrawItFocused := false;
  4407.               end;
  4408.             if GridPen.Effect = geNone then
  4409.               Exit;
  4410.  
  4411.             RowOfs := tbRowNums^.Ay[RowInx].Offset;
  4412.             Ht := tbRowNums^.Ay[succ(RowInx)].Offset - RowOfs;
  4413.             ColOfs := tbColNums^.Ay[ColInx].Offset;
  4414.             Wd := tbColNums^.Ay[succ(ColInx)].Offset - ColOfs;
  4415.  
  4416.             {calculate where to draw the vertical/horizontal lines}
  4417.             case GridPenSet.NormalGrid.Effect of
  4418.               geNone      : begin
  4419.                               ActRowOfs := RowOfs;
  4420.                               ActRowBottom := RowOfs+Ht-1;
  4421.                               ActColOfs := ColOfs;
  4422.                               ActColRight := ColOfs+Wd-1
  4423.                             end;
  4424.               geVertical  : begin
  4425.                               ActRowOfs := RowOfs;
  4426.                               ActRowBottom := RowOfs+Ht-1;
  4427.                               ActColOfs := ColOfs;
  4428.                               ActColRight := ColOfs+Wd-2;
  4429.                             end;
  4430.               geHorizontal: begin
  4431.                               ActRowOfs := RowOfs;
  4432.                               ActRowBottom := RowOfs+Ht-2;
  4433.                               ActColOfs := ColOfs;
  4434.                               ActColRight := ColOfs+Wd-1;
  4435.                             end;
  4436.               geBoth      : begin
  4437.                               ActRowOfs := RowOfs;
  4438.                               ActRowBottom := RowOfs+Ht-2;
  4439.                               ActColOfs := ColOfs;
  4440.                               ActColRight := ColOfs+Wd-2;
  4441.                             end;
  4442.               ge3D        : begin
  4443.                               ActRowOfs := RowOfs+1;
  4444.                               ActRowBottom := RowOfs+Ht-2;
  4445.                               ActColOfs := ColOfs+1;
  4446.                               ActColRight := ColOfs+Wd-2;
  4447.                             end;
  4448.             end;{case}
  4449.  
  4450.             {get the correct background color for the pen}
  4451.             if DrawItFocused then
  4452.                  BrushColor := Colors.ActiveFocused
  4453.             else BrushColor := Colors.ActiveUnfocused;
  4454.             Brush.Color := Color;
  4455.  
  4456.             {$IFDEF Win32}
  4457.             Windows.SetBkColor(Handle, ColorToRGB(BrushColor));
  4458.             {$ELSE}
  4459.             WinProcs.SetBkColor(Handle, ColorToRGB(BrushColor));
  4460.             {$ENDIF}
  4461.  
  4462.             {set up the pen}
  4463.             with Pen do
  4464.               begin
  4465.                 Width := 1;
  4466.                 Style := GridPen.Style;
  4467.                 Color := GridPen.NormalColor;
  4468.               end;
  4469.  
  4470.             {right line}
  4471.             if GridPen.Effect in [geVertical, geBoth, ge3D] then
  4472.               begin
  4473.                 MoveTo(ActColRight, ActRowOfs);
  4474.                 LineTo(ActColRight, ActRowBottom+1);
  4475.               end;
  4476.             {bottom line}
  4477.             if GridPen.Effect in [geHorizontal, geBoth, ge3D] then
  4478.               begin
  4479.                 MoveTo(ActColOfs, ActRowBottom);
  4480.                 LineTo(ActColRight+1, ActRowBottom);
  4481.               end;
  4482.  
  4483.             {if in 3D, must change colors}
  4484.             if (GridPen.Effect = ge3D) then
  4485.               Pen.Color := GridPen.SecondColor;
  4486.  
  4487.             {left line}
  4488.             if GridPen.Effect in [geVertical, geBoth, ge3D] then
  4489.               begin
  4490.                 MoveTo(ActColOfs, ActRowOfs);
  4491.                 LineTo(ActColOfs, ActRowBottom+1);
  4492.               end;
  4493.             {top line}
  4494.             if GridPen.Effect in [geHorizontal, geBoth, ge3D] then
  4495.               begin
  4496.                 MoveTo(ActColOfs, ActRowOfs);
  4497.                 LineTo(ActColRight+1, ActRowOfs);
  4498.               end;
  4499.           end;
  4500.       end;
  4501.   end;
  4502. {--------}
  4503. procedure TOvcCustomTable.tbDrawCells(RowInxStart, RowInxEnd : integer;
  4504.                                       ColInxStart, ColInxEnd : integer);
  4505.   var
  4506.     RowInx : integer;
  4507.   begin
  4508.     {Delphi bug fix - refresh the canvas handle to force brush to be recreated}
  4509.     Canvas.Refresh;
  4510.     {draw cells that need it}
  4511.     with tbRowNums^ do
  4512.       for RowInx := RowInxStart to RowInxEnd do
  4513.         tbDrawRow(RowInx, ColInxStart, ColInxEnd);
  4514.   end;
  4515. {--------}
  4516. procedure TOvcCustomTable.tbDrawInvalidCells(InvCells : TOvcCellArray);
  4517.   var
  4518.     RowInx     : integer;
  4519.     ColInx     : integer;
  4520.     EndColInx  : integer;
  4521.     CellInx    : integer;
  4522.     NextCellInx: integer;
  4523.     OldRowNum  : TRowNum;
  4524.     CellAddr   : TOvcCellAddress;
  4525.     NewCellAddr: TOvcCellAddress;
  4526.     EndCol     : TColNum;
  4527.     ContinueTrying : boolean;
  4528.   begin
  4529.     if (InvCells.Count > 0) then
  4530.       begin
  4531.         {Delphi bug fix - refresh the canvas handle to force brush to be recreated}
  4532.         Canvas.Refresh;
  4533.         {set up for while loop}
  4534.         OldRowNum := -1;
  4535.         CellInx := 0;
  4536.         while (CellInx < InvCells.Count) do
  4537.           begin
  4538.             InvCells.GetCellAddr(CellInx, CellAddr);
  4539.             RowInx := tbFindRowInx(CellAddr.Row);
  4540.             if (RowInx <> -1) then
  4541.               begin
  4542.                 ColInx := tbFindColInx(CellAddr.Col);
  4543.                 if (ColInx <> -1) then
  4544.                   begin
  4545.                     {have we switched rows?}
  4546.                     if (OldRowNum <> CellAddr.Row) then
  4547.                       OldRowNum := CellAddr.Row;
  4548.                     {try and get a block of columns}
  4549.                     EndCol := CellAddr.Col;
  4550.                     NextCellInx := succ(CellInx);
  4551.                     ContinueTrying := true;
  4552.                     while ContinueTrying do
  4553.                       begin
  4554.                         if (NextCellInx >= InvCells.Count) then
  4555.                           ContinueTrying := false
  4556.                         else
  4557.                           begin
  4558.                             InvCells.GetCellAddr(NextCellInx, NewCellAddr);
  4559.                             if (OldRowNum = NewCellAddr.Row) and
  4560.                                (NewCellAddr.Col = succ(EndCol)) then
  4561.                               begin
  4562.                                 EndCol := NewCellAddr.Col;
  4563.                                 inc(NextCellInx);
  4564.                               end
  4565.                             else
  4566.                               ContinueTrying := false;
  4567.                           end
  4568.                       end;
  4569.                     if (EndCol <> CellAddr.Col) then
  4570.                       begin
  4571.                         EndColInx := tbFindColInx(EndCol);
  4572.                         CellInx := pred(NextCellInx);
  4573.                         {just in case (hidden cols perhaps?)}
  4574.                         while (EndColInx = -1) do
  4575.                           begin
  4576.                             dec(EndCol);
  4577.                             EndColInx := tbFindColInx(EndCol);
  4578.                           end
  4579.                       end
  4580.                     else
  4581.                       EndColInx := ColInx;
  4582.                     tbDrawRow(RowInx, ColInx, EndColInx);
  4583.                   end;
  4584.               end;
  4585.             inc(CellInx);
  4586.           end;
  4587.       end;
  4588.     if InvCells.MustDoUnusedBit then
  4589.       DoPaintUnusedArea;
  4590.     InvCells.Clear;
  4591.   end;
  4592. {--------}
  4593. procedure TOvcCustomTable.tbDrawMoveLine;
  4594.   var
  4595.     OldPen : TPen;
  4596.     MoveOffset : integer;
  4597.   begin
  4598.     if tbDrag <> nil then
  4599.       tbDrag.HideDragImage;
  4600.     if (otsMoving in tbState) then
  4601.       with Canvas do
  4602.         begin
  4603.           OldPen := TPen.Create;
  4604.           try
  4605.             OldPen.Assign(Pen);
  4606.             try
  4607.               Pen.Mode := pmXor;
  4608.               Pen.Style := psSolid;
  4609.               Pen.Color := clWhite;
  4610.               Pen.Width := 3;
  4611.               if (otsDoingCol in tbState) then
  4612.                 begin
  4613.                   if (tbMoveIndex < tbMoveIndexTo) then
  4614.                     MoveOffset := tbColNums^.Ay[succ(tbMoveIndexTo)].Offset
  4615.                   else
  4616.                     MoveOffset := tbColNums^.Ay[tbMoveIndexTo].Offset;
  4617.                   MoveTo(MoveOffset, 0);
  4618.                   LineTo(MoveOffset, ClientHeight);
  4619.                 end
  4620.               else {doing row}
  4621.                 begin
  4622.                   if (tbMoveIndex < tbMoveIndexTo) then
  4623.                     MoveOffset := tbRowNums^.Ay[succ(tbMoveIndexTo)].Offset
  4624.                   else
  4625.                     MoveOffset := tbRowNums^.Ay[tbMoveIndexTo].Offset;
  4626.                   MoveTo(0, MoveOffset);
  4627.                   LineTo(ClientWidth, MoveOffset);
  4628.                 end
  4629.             finally
  4630.               Canvas.Pen := OldPen;
  4631.             end;{try..finally}
  4632.           finally
  4633.             OldPen.Free;
  4634.           end;{try..finally}
  4635.         end;
  4636.     if tbDrag <> nil then
  4637.       tbDrag.ShowDragImage;
  4638.   end;
  4639. {--------}
  4640. procedure TOvcCustomTable.tbDrawRow(RowInx : integer; ColInxStart, ColInxEnd : integer);
  4641.   var
  4642.     RowOfs    : integer;
  4643.     RowHt     : integer;
  4644.     RowNum    : TRowNum;
  4645.     ColInx    : integer;
  4646.     ColNum    : TColNum;
  4647.     ColOfs    : integer;
  4648.     ColWd     : integer;
  4649.     Cell      : TOvcBaseTableCell;
  4650.     Data      : pointer;
  4651.     GridPen   : TOvcGridPen;
  4652.     BrushColor: TColor;
  4653.     CellAttr  : TOvcCellAttributes;
  4654.     DestRect  : TRect;
  4655.     RowIsLocked : boolean;
  4656.     ColIsLocked : boolean;
  4657.     IsActiveRow : boolean;
  4658.   begin
  4659.     {calculate data about the row, tell the user we're entering the row}
  4660.     with tbRowNums^ do
  4661.       begin
  4662.         RowNum := Ay[RowInx].Number;
  4663.         RowOfs := Ay[RowInx].Offset;
  4664.         RowHt := Ay[succ(RowInx)].Offset - RowOfs;
  4665.       end;
  4666.     IsActiveRow := ActiveRow = RowNum;
  4667.     RowIsLocked := RowNum < LockedRows;
  4668.     DoEnteringRow(RowNum);
  4669.  
  4670.     {set up the cell attribute record}
  4671.     FillChar(CellAttr, sizeof(CellAttr), 0);
  4672.     CellAttr.caFont := tbCellAttrFont;
  4673.  
  4674.     {for all required cells}
  4675.     for ColInx := ColInxEnd downto ColInxStart do
  4676.       begin
  4677.         {calculate data about the column, tell the user we're entering the column}
  4678.         with tbColNums^ do
  4679.           begin
  4680.             ColNum := Ay[ColInx].Number;
  4681.             ColOfs := Ay[ColInx].Offset;
  4682.             ColWd := Ay[succ(ColInx)].Offset - ColOfs;
  4683.           end;
  4684.         ColIsLocked := (ColNum < LockedCols);
  4685.         DoEnteringColumn(ColNum);
  4686.  
  4687.         {get the gridpen for the cell}
  4688.         if (RowIsLocked or ColIsLocked) then
  4689.           GridPen := GridPenSet.LockedGrid
  4690.         else
  4691.           GridPen := GridPenSet.NormalGrid;
  4692.  
  4693.         {calculate row height/column width available to the cell}
  4694.         DestRect := Rect(ColOfs, RowOfs, ColOfs+ColWd, RowOfs+RowHt);
  4695.         case GridPen.Effect of
  4696.           geVertical  : dec(DestRect.Right);
  4697.           geHorizontal: dec(DestRect.Bottom);
  4698.           geBoth      : begin
  4699.                           dec(DestRect.Right);
  4700.                           dec(DestRect.Bottom);
  4701.                         end;
  4702.           ge3D        : InflateRect(DestRect, -1, -1);
  4703.         end;{case}
  4704.  
  4705.         {don't do painting for the cell being edited}
  4706.         Cell := nil;
  4707.         if not (IsActiveRow and (ColNum = ActiveCol) and
  4708.                 (InEditingState)) then
  4709.           begin
  4710.             {get the cell}
  4711.             Cell := tbFindCell(RowNum, ColNum);
  4712.             if Assigned(Cell) then
  4713.               begin
  4714.                 {paint it}
  4715.                 DoGetCellData(RowNum, ColNum, Data, cdpForPaint);
  4716.                 CellAttr.caFont.Assign(Font);
  4717.                 Cell.ResolveAttributes(RowNum, ColNum, CellAttr);
  4718.                 Cell.Paint(Canvas, DestRect,
  4719.                            RowNum, ColNum,
  4720.                            CellAttr,
  4721.                            Data);
  4722.               end
  4723.           end;
  4724.  
  4725.         {if no cell found or it's the active cell in editing mode
  4726.          clear the rectangle}
  4727.         if not Assigned(Cell) or
  4728.            (IsActiveRow and (ColNum = ActiveCol) and InEditingState) then
  4729.           begin
  4730.             with CellAttr do
  4731.               begin
  4732.                 caAccess := otxDefault;
  4733.                 caAdjust := otaDefault;
  4734.                 caColor := Color;
  4735.                 caFont.Assign(Font);
  4736.                 caFontColor := Font.Color;
  4737.               end;
  4738.             ResolveCellAttributes(RowNum, ColNum, CellAttr);
  4739.             Canvas.Brush.Color := CellAttr.caColor;
  4740.             Canvas.FillRect(DestRect);
  4741.           end;
  4742.  
  4743.         {Check to see if there is a grid to display}
  4744.         if (GridPen.Effect <> geNone) then
  4745.           with Canvas do
  4746.             begin
  4747.               {Get ready to draw the cell's grid}
  4748.               BrushColor := Color;
  4749.               Brush.Color := BrushColor;
  4750.               Pen.Style := GridPen.Style;
  4751.               Pen.Width := 1;
  4752.  
  4753.               {$IFDEF Win32}
  4754.               Windows.SetBkColor(Handle, ColorToRGB(BrushColor));
  4755.               {$ELSE}
  4756.               WinProcs.SetBkColor(Handle, ColorToRGB(BrushColor));
  4757.               {$ENDIF}
  4758.  
  4759.               {draw the top and left lines, only if required of course}
  4760.               if (GridPen.Effect = ge3D) then
  4761.                 begin
  4762.                   {set the pen color for the top & left}
  4763.                   Pen.Color := GridPen.SecondColor;
  4764.                   {draw the lines}
  4765.                   MoveTo(ColOfs, pred(RowOfs+RowHt));
  4766.                   LineTo(ColOfs, RowOfs);
  4767.                   LineTo(ColOfs+ColWd, RowOfs);
  4768.                 end;
  4769.  
  4770.               {set the pen color for the bottom & right}
  4771.               Pen.Color := GridPen.NormalColor;
  4772.  
  4773.               {draw right line}
  4774.               if (GridPen.Effect <> geHorizontal) then
  4775.                 begin
  4776.                   MoveTo(ColOfs+ColWd-1, RowOfs);
  4777.                   LineTo(ColOfs+ColWd-1, RowOfs+RowHt);
  4778.                 end;
  4779.  
  4780.               {draw bottom line}
  4781.               if (GridPen.Effect <> geVertical) then
  4782.                 begin
  4783.                   MoveTo(ColOfs, pred(RowOfs+RowHt));
  4784.                   LineTo(ColOfs+ColWd, pred(RowOfs+RowHt));
  4785.                 end;
  4786.             end;
  4787.       end;
  4788.   end;
  4789. {--------}
  4790. procedure TOvcCustomTable.tbDrawSizeLine;
  4791.   var
  4792.     OldPen : TPen;
  4793.   begin
  4794.     if (otsSizing in tbState) then
  4795.       with Canvas do
  4796.         begin
  4797.           OldPen := TPen.Create;
  4798.           try
  4799.             OldPen.Assign(Pen);
  4800.             Pen.Color := clBlack;
  4801.             Pen.Mode := pmXor;
  4802.             Pen.Style := psDot;
  4803.             Pen.Width := 1;
  4804.             if (otsDoingRow in tbState) then
  4805.               begin
  4806.                 MoveTo(0, tbSizeOffset);
  4807.                 LineTo(ClientWidth, tbSizeOffset);
  4808.               end
  4809.             else
  4810.               begin
  4811.                 MoveTo(tbSizeOffset, 0);
  4812.                 LineTo(tbSizeOffset, ClientHeight);
  4813.               end;
  4814.           finally
  4815.             Canvas.Pen := OldPen;
  4816.             OldPen.Free;
  4817.           end;{try..finally}
  4818.         end;
  4819.   end;
  4820. {--------}
  4821. procedure TOvcCustomTable.tbDrawUnusedBit;
  4822.   var
  4823.     R  : TRect;
  4824.     CR : TRect;
  4825.     ChangedBrush : boolean;
  4826.   begin
  4827.     ChangedBrush := false;
  4828.     {$IFDEF Win32}
  4829.     Windows.GetClientRect(Handle, CR);
  4830.     {$ELSE}
  4831.     WinProcs.GetClientRect(Handle, CR);
  4832.     {$ENDIF}
  4833.     with R, tbColNums^ do
  4834.       begin
  4835.         Left := Ay[Count].Offset;
  4836.         Right := CR.Right;
  4837.         Top := 0;
  4838.         Bottom := CR.Bottom;
  4839.       end;
  4840.     if (R.Left < R.Right) then
  4841.       with Canvas do
  4842.         begin
  4843.           Brush.Color := ColorUnused;
  4844.           FillRect(R);
  4845.           ChangedBrush := true;
  4846.         end;
  4847.  
  4848.     with R, tbRowNums^ do
  4849.       begin
  4850.         Right := Left;
  4851.         Left := 0;
  4852.         Top := Ay[Count].Offset;
  4853.       end;
  4854.     if (R.Top < R.Bottom) then
  4855.       with Canvas do
  4856.         begin
  4857.           if not ChangedBrush then
  4858.             Brush.Color := ColorUnused;
  4859.           FillRect(R);
  4860.         end;
  4861.   end;
  4862. {--------}
  4863. procedure TOvcCustomTable.Paint;
  4864.   var
  4865.     UR, GR : TRect;
  4866.     WhatToPaint : integer;
  4867.     RowInx      : integer;
  4868.     ColInx      : integer;
  4869.   begin
  4870.     {don't do anything if the table is locked from drawing and
  4871.      there is no scrolling going on (tbMustUpdate is *only* set in
  4872.      the tbScrollTableXxx methods to force an update).}
  4873.     if (tbLockCount > 0) and (not tbMustUpdate) then
  4874.       begin
  4875.         Exit;
  4876.       end;
  4877.  
  4878.     if tbDrag <> nil then
  4879.       tbDrag.HideDragImage;
  4880.  
  4881.     {$IFDEF Win32}
  4882.     Windows.GetClipBox(Canvas.Handle, UR);
  4883.     {$ELSE}
  4884.     WinProcs.GetClipBox(Canvas.Handle, UR);
  4885.     {$ENDIF}
  4886.     WhatToPaint := tbCalcCellsFromRect(UR, GR);
  4887.  
  4888.     if (WhatToPaint = 0) and
  4889.        (otsEditing in tbState) and
  4890.        ((GR.Top = ActiveRow) and (GR.Bottom = ActiveRow) and
  4891.         (GR.Left = ActiveCol) and (GR.Right = ActiveCol)) then
  4892.       Exit;
  4893.  
  4894.     {if we are actually processing a WM_PAINT message, then paint the
  4895.      invalid cells, etc}
  4896.     if (tbLockCount = 0) then
  4897.       begin
  4898.         if (WhatToPaint <> 2) then
  4899.           tbDrawCells(GR.Top, GR.Bottom, GR.Left, GR.Right);
  4900.  
  4901.         if (WhatToPaint <> 0) then
  4902.           DoPaintUnusedArea;
  4903.  
  4904.         tbDrawActiveCell;
  4905.       end
  4906.     {otherwise we are in the middle of a scroll operation, so just invalidate
  4907.      the cells that need it}
  4908.     else {tbLockCount > 0, ie tbMustUpdate is true}
  4909.       begin
  4910.         if (WhatToPaint <> 2) then
  4911.           for RowInx := GR.Top to GR.Bottom do
  4912.             for ColInx := GR.Left to GR.Right do
  4913.               InvalidateCell(tbRowNums^.Ay[RowInx].Number, tbColNums^.Ay[ColInx].Number);
  4914.         if (WhatToPaint <> 0) then
  4915.           tbInvCells.AddUnusedBit;
  4916.         tbMustUpdate := false;
  4917.       end;
  4918.  
  4919.     if tbDrag <> nil then
  4920.       tbDrag.ShowDragImage;
  4921.  
  4922.   end;
  4923. {====================================================================}
  4924.  
  4925.  
  4926. {==TOvcTable event handlers==========================================}
  4927. procedure TOvcCustomTable.DoActiveCellChanged(RowNum : TRowNum; ColNum : TColNum);
  4928.   begin
  4929.     if ((ComponentState * [csLoading, csDestroying]) = []) and
  4930.        Assigned(FActiveCellChanged) then
  4931.       FActiveCellChanged(Self, RowNum, ColNum);
  4932.   end;
  4933. {--------}
  4934. procedure TOvcCustomTable.DoActiveCellMoving(Command : word;
  4935.                                          var RowNum : TRowNum;
  4936.                                          var ColNum : TColNum);
  4937.   begin
  4938.     if ((ComponentState * [csLoading, csDestroying]) <> []) then
  4939.       Exit;
  4940.     if Assigned(FActiveCellMoving) then
  4941.       FActiveCellMoving(Self, Command, RowNum, ColNum);
  4942.     if InEditingState and ((RowNum <> ActiveRow) or (ColNum <> ActiveCol)) then
  4943.       if not StopEditingState(true) then
  4944.         begin
  4945.           RowNum := ActiveRow;
  4946.           ColNum := ActiveCol;
  4947.           Exit;
  4948.         end;
  4949.   end;
  4950. {--------}
  4951. procedure TOvcCustomTable.DoBeginEdit(RowNum : TRowNum; ColNum : TColNum;
  4952.                                   var AllowIt : boolean);
  4953.   begin
  4954.     if ((ComponentState * [csLoading, csDestroying]) <> []) then
  4955.       AllowIt := false
  4956.     else
  4957.       begin
  4958.         AllowIt := true;
  4959.         if Assigned(FBeginEdit) then
  4960.           FBeginEdit(Self, RowNum, ColNum, AllowIt);
  4961.       end;
  4962.   end;
  4963. {--------}
  4964. procedure TOvcCustomTable.DoClipboardCopy;
  4965.   begin
  4966.     if ((ComponentState * [csLoading, csDestroying]) = []) and
  4967.        Assigned(FClipboardCopy) then
  4968.       FClipboardCopy(Self);
  4969.   end;
  4970. {--------}
  4971. procedure TOvcCustomTable.DoClipboardCut;
  4972.   begin
  4973.     if ((ComponentState * [csLoading, csDestroying]) = []) and
  4974.        Assigned(FClipboardCut) then
  4975.       FClipboardCut(Self);
  4976.   end;
  4977. {--------}
  4978. procedure TOvcCustomTable.DoClipboardPaste;
  4979.   begin
  4980.     if ((ComponentState * [csLoading, csDestroying]) = []) and
  4981.        Assigned(FClipboardPaste) then
  4982.       FClipboardPaste(Self);
  4983.   end;
  4984. {--------}
  4985. procedure TOvcCustomTable.DoColumnsChanged(ColNum1, ColNum2 : TColNum;
  4986.                                            Action : TOvcTblActions);
  4987.   var
  4988.     i : integer;
  4989.   begin
  4990.     for i := 0 to pred(taCellList.Count) do
  4991.       if (TOvcTableCellAncestor(taCellList[i]) is TOvcTCColHead) then
  4992.         TOvcTCColHead(taCellList[i]).chColumnsChanged(ColNum1, ColNum2, Action);
  4993.  
  4994.     if ((ComponentState * [csLoading, csDestroying]) = []) and
  4995.        Assigned(FColumnsChanged) then
  4996.       FColumnsChanged(Self, ColNum1, ColNum2, Action);
  4997.   end;
  4998. {--------}
  4999. procedure TOvcCustomTable.DoDoneEdit(RowNum : TRowNum; ColNum : TColNum);
  5000.   begin
  5001.     if ((ComponentState * [csLoading, csDestroying]) = []) and
  5002.        Assigned(FDoneEdit) then
  5003.       FDoneEdit(Self, RowNum, ColNum);
  5004.   end;
  5005. {--------}
  5006. procedure TOvcCustomTable.DoEndEdit(Cell : TOvcBaseTableCell;
  5007.                                     RowNum : TRowNum; ColNum : TColNum;
  5008.                                 var AllowIt : boolean);
  5009.   begin
  5010.     if ((ComponentState * [csLoading, csDestroying]) <> []) then
  5011.       AllowIt := false
  5012.     else
  5013.       begin
  5014.         AllowIt := true;
  5015.         if Assigned(FEndEdit) then
  5016.           FEndEdit(Self, Cell, RowNum, ColNum, AllowIt);
  5017.       end;
  5018.   end;
  5019. {--------}
  5020. procedure TOvcCustomTable.DoEnteringColumn(ColNum : TColNum);
  5021.   begin
  5022.     if (ColNum <> tbLastEntCol) then
  5023.       begin
  5024.         tbLastEntCol := ColNum;
  5025.         if ((ComponentState * [csLoading, csDestroying]) = []) and
  5026.            Assigned(FEnteringColumn) then
  5027.           FEnteringColumn(Self, ColNum);
  5028.       end;
  5029.   end;
  5030. {--------}
  5031. procedure TOvcCustomTable.DoEnteringRow(RowNum : TRowNum);
  5032.   begin
  5033.     if (RowNum <> tbLastEntRow) then
  5034.       begin
  5035.         tbLastEntRow := RowNum;
  5036.         if ((ComponentState * [csLoading, csDestroying]) = []) and
  5037.            Assigned(FEnteringRow) then
  5038.           FEnteringRow(Self, RowNum);
  5039.       end;
  5040.   end;
  5041. {--------}
  5042. procedure TOvcCustomTable.DoGetCellAttributes(RowNum : TRowNum; ColNum : TColNum;
  5043.                                           var CellAttr : TOvcCellAttributes);
  5044.   begin
  5045.     if ((ComponentState * [csLoading, csDestroying]) = []) and
  5046.        Assigned(FGetCellAttributes) then
  5047.       FGetCellAttributes(Self, RowNum, ColNum, CellAttr);
  5048.   end;
  5049. {--------}
  5050. procedure TOvcCustomTable.DoGetCellData(RowNum  : TRowNum; ColNum : TColNum;
  5051.                                     var Data    : pointer;
  5052.                                         Purpose : TOvcCellDataPurpose);
  5053.   begin
  5054.     Data := nil;
  5055.     if ((ComponentState * [csLoading, csDestroying]) = []) and
  5056.        HandleAllocated and
  5057.        Assigned(FGetCellData) then
  5058.       FGetCellData(Self, RowNum, ColNum, Data, Purpose);
  5059.   end;
  5060. {--------}
  5061. procedure TOvcCustomTable.DoLeavingColumn(ColNum : TColNum);
  5062.   begin
  5063.     if ((ComponentState * [csLoading, csDestroying]) = []) and
  5064.        Assigned(FLeavingColumn) then
  5065.       FLeavingColumn(Self, ColNum);
  5066.   end;
  5067. {--------}
  5068. procedure TOvcCustomTable.DoLeavingRow(RowNum : TRowNum);
  5069.   begin
  5070.     if ((ComponentState * [csLoading, csDestroying]) = []) and
  5071.        Assigned(FLeavingRow) then
  5072.       FLeavingRow(Self, RowNum);
  5073.   end;
  5074. {--------}
  5075. procedure TOvcCustomTable.DoLockedCellClick(RowNum : TRowNum; ColNum : TColNum);
  5076.   begin
  5077.     if ((ComponentState * [csLoading, csDestroying]) = []) and
  5078.        Assigned(FLockedCellClick) then
  5079.       FLockedCellClick(Self, RowNum, ColNum);
  5080.   end;
  5081. {--------}
  5082.  
  5083. {$IFDEF WIN32}
  5084. procedure TOvcCustomTable.DoOnMouseWheel(Shift : TShiftState; Delta, XPos, YPos : SmallInt);
  5085. begin
  5086.   inherited DoOnMouseWheel(Shift, Delta, XPos, YPos);
  5087.  
  5088.   if Delta < 0 then
  5089.     MoveActiveCell(ccDown)
  5090.   else
  5091.     MoveActiveCell(ccUp);
  5092. end;
  5093. {$ENDIF}
  5094.  
  5095. procedure TOvcCustomTable.DoPaintUnusedArea;
  5096.   begin
  5097.     if ((ComponentState * [csLoading, csDestroying]) <> []) then
  5098.       Exit;
  5099.     if Assigned(FPaintUnusedArea) then
  5100.       FPaintUnusedArea(Self)
  5101.     else
  5102.       tbDrawUnusedBit;
  5103.   end;
  5104. {--------}
  5105. procedure TOvcCustomTable.DoRowsChanged(RowNum1, RowNum2 : TRowNum;
  5106.                                         Action : TOvcTblActions);
  5107.   begin
  5108.     if ((ComponentState * [csLoading, csDestroying]) = []) and
  5109.        Assigned(FRowsChanged) then
  5110.       FRowsChanged(Self, RowNum1, RowNum2, Action);
  5111.   end;
  5112. {--------}
  5113. procedure TOvcCustomTable.DoSizeCellEditor(RowNum   : TRowNum;
  5114.                                            ColNum   : TColNum;
  5115.                                        var CellRect : TRect;
  5116.                                        var CellStyle: TOvcTblEditorStyle);
  5117.   begin
  5118.     if Assigned(FSizeCellEditor) then
  5119.       FSizeCellEditor(Self, RowNum, ColNum, CellRect, CellStyle);
  5120.   end;
  5121. {--------}
  5122. procedure TOvcCustomTable.DoTopLeftCellChanged(RowNum : TRowNum; ColNum : TColNum);
  5123.   begin
  5124.     if ((ComponentState * [csLoading, csDestroying]) = []) and
  5125.        Assigned(FTopLeftCellChanged) then
  5126.       FTopLeftCellChanged(Self, RowNum, ColNum);
  5127.   end;
  5128. {--------}
  5129. procedure TOvcCustomTable.DoTopLeftCellChanging(var RowNum : TRowNum;
  5130.                                                 var ColNum : TColNum);
  5131.   begin
  5132.     if ((ComponentState * [csLoading, csDestroying]) = []) and
  5133.        Assigned(FTopLeftCellChanging) then
  5134.       FTopLeftCellChanging(Self, RowNum, ColNum);
  5135.   end;
  5136. {--------}
  5137. procedure TOvcCustomTable.DoUserCommand(Cmd : word);
  5138.   begin
  5139.     if ((ComponentState * [csLoading, csDestroying]) = []) and
  5140.        Assigned(FUserCommand) then
  5141.       FUserCommand(Self, Cmd);
  5142.   end;
  5143. {====================================================================}
  5144.  
  5145.  
  5146. {==TOvcTable Windows Message handlers================================}
  5147. procedure TOvcCustomTable.CMColorChanged(var Msg : TMessage);
  5148.   begin
  5149.     inherited;
  5150.     AllowRedraw := false;
  5151.     tbNotifyCellsOfTableChange;
  5152.     AllowRedraw := true;
  5153.   end;
  5154. {--------}
  5155. procedure TOvcCustomTable.CMCtl3DChanged(var Msg : TMessage);
  5156.   begin
  5157.     if (csLoading in ComponentState) or not HandleAllocated then
  5158.       Exit;
  5159.  
  5160.     {$IFDEF Win32}
  5161.     if NewStyleControls and (FBorderStyle = bsSingle) then
  5162.       RecreateWnd;
  5163.     {$ENDIF}
  5164.  
  5165.     inherited;
  5166.   end;
  5167. {--------}
  5168. procedure TOvcCustomTable.CMDesignHitTest(var Msg : TCMDesignHitTest);
  5169.   var
  5170.     IsVert     : boolean;
  5171.     IsColMove  : boolean;
  5172.     OnGridLine : boolean;
  5173.   begin
  5174.     Msg.Result := 1;
  5175.     if (otsDesigning in tbState) then
  5176.       begin
  5177.         if ((tbState * [otsSizing, otsMoving]) <> []) then
  5178.           Exit;
  5179.         Msg.Result := 0;
  5180.         OnGridLine := tbIsOnGridLine(Msg.Pos.X, Msg.Pos.Y, IsVert);
  5181.         if OnGridLine then
  5182.           Msg.Result := 1
  5183.         else
  5184.           Msg.Result := longint(tbIsInMoveArea(Msg.Pos.X, Msg.Pos.Y, IsColMove));
  5185.       end;
  5186.   end;
  5187. {--------}
  5188. procedure TOvcCustomTable.CMFontChanged(var Msg : TMessage);
  5189.   begin
  5190.     inherited;
  5191.     AllowRedraw := false;
  5192.     tbNotifyCellsOfTableChange;
  5193.     AllowRedraw := true;
  5194.   end;
  5195. {--------}
  5196. procedure TOvcCustomTable.ctimQueryOptions(var Msg : TMessage);
  5197.   begin
  5198.     Msg.Result := longint(word(FOptions));
  5199.   end;
  5200. {--------}
  5201. procedure TOvcCustomTable.ctimQueryColor(var Msg : TMessage);
  5202.   begin
  5203.     Msg.Result := longint(Color);
  5204.   end;
  5205. {--------}
  5206. procedure TOvcCustomTable.ctimQueryFont(var Msg : TMessage);
  5207.   begin
  5208.     Msg.Result := longint(Font);
  5209.   end;
  5210. {--------}
  5211. procedure TOvcCustomTable.ctimQueryLockedCols(var Msg : TMessage);
  5212.   begin
  5213.     Msg.Result := longint(LockedCols);
  5214.   end;
  5215. {--------}
  5216. procedure TOvcCustomTable.ctimQueryLockedRows(var Msg : TMessage);
  5217.   begin
  5218.     Msg.Result := longint(LockedRows);
  5219.   end;
  5220. {--------}
  5221. procedure TOvcCustomTable.ctimQueryActiveCol(var Msg : TMessage);
  5222.   begin
  5223.     Msg.Result := longint(ActiveCol);
  5224.   end;
  5225. {--------}
  5226. procedure TOvcCustomTable.ctimQueryActiveRow(var Msg : TMessage);
  5227.   begin
  5228.     Msg.Result := longint(ActiveRow);
  5229.   end;
  5230. {--------}
  5231. procedure TOvcCustomTable.ctimRemoveCell(var Msg : TMessage);
  5232.   begin
  5233.     Notification(TComponent(Msg.LParam), opRemove);
  5234.     Msg.Result := 0;
  5235.   end;
  5236. {--------}
  5237. procedure TOvcCustomTable.ctimStartEdit(var Msg : TMessage);
  5238.   begin
  5239.     if not StartEditingState then
  5240.       begin
  5241.         AllowRedraw := false;
  5242.         InvalidateCell(ActiveRow, ActiveCol);
  5243.         AllowRedraw := true;
  5244.       end;
  5245.     Msg.Result := 1;
  5246.   end;
  5247. {--------}
  5248. procedure TOvcCustomTable.ctimStartEditMouse(var Msg : TWMMouse);
  5249.   begin
  5250.     if Assigned(tbActCell) and InEditingState then
  5251.       if tbActCell.AcceptActivationClick then
  5252.         begin
  5253.           {$IFDEF Win32}
  5254.           Windows.SetFocus(tbActCell.EditHandle);
  5255.           {$ELSE}
  5256.           WinProcs.SetFocus(tbActCell.EditHandle);
  5257.           {$ENDIF}
  5258.           PostMessage(tbActCell.EditHandle,
  5259.                       WM_LBUTTONDOWN,
  5260.                       Msg.Keys, longint(Msg.Pos))
  5261.         end;
  5262.     Msg.Result := 1;
  5263.   end;
  5264. {--------}
  5265. procedure TOvcCustomTable.ctimStartEditKey(var Msg : TWMKey);
  5266.   begin
  5267.     if Assigned(tbActCell) and InEditingState then
  5268.       begin
  5269.         {$IFDEF Win32}
  5270.         Windows.SetFocus(tbActCell.EditHandle);
  5271.         {$ELSE}
  5272.         WinProcs.SetFocus(tbActCell.EditHandle);
  5273.         {$ENDIF}
  5274.         PostMessage(tbActCell.EditHandle, WM_KEYDOWN, Msg.CharCode, Msg.KeyData);
  5275.       end;
  5276.     Msg.Result := 1;
  5277.   end;
  5278. {--------}
  5279. {$IFDEF Win32}
  5280. procedure TOvcCustomTable.ctimLoadDefaultCells(var Msg : TMessage);
  5281.   begin
  5282.     AllowRedraw := false;
  5283.     tbFinishLoadingCellList;
  5284.     tbFinishLoadingDefaultCells;
  5285.     Msg.Result := 0;
  5286.     tbMustFinishLoading := false;
  5287.     AllowRedraw := true;
  5288.   end;
  5289. {$ENDIF}
  5290. {--------}
  5291. procedure TOvcCustomTable.WMCancelMode(var Msg : TMessage);
  5292.   begin
  5293.     inherited;
  5294.     tbIsKeySelecting := false;
  5295.     if (otsMouseSelect in tbState) then
  5296.       tbState := tbState - [otsMouseSelect] + [otsNormal];
  5297.   end;
  5298. {--------}
  5299. procedure TOvcCustomTable.WMEraseBkGnd(var Msg : TWMEraseBkGnd);
  5300.   begin
  5301.     Msg.Result := 1; {no erasing of the background, we'll do it all}
  5302.   end;
  5303. {--------}
  5304. procedure TOvcCustomTable.WMGetDlgCode(var Msg : TMessage);
  5305.   begin
  5306.     Msg.Result := DLGC_WANTCHARS or DLGC_WANTARROWS;
  5307.     if (otoTabToArrow in Options) then
  5308.       Msg.Result := Msg.Result or DLGC_WANTTAB;
  5309.   end;
  5310. {--------}
  5311. procedure TOvcCustomTable.WMHScroll(var Msg : TWMScroll);
  5312.   {------}
  5313.   procedure ProcessThumb;
  5314.     var
  5315.       i : integer;
  5316.       NewLeftCol : TColNum;
  5317.     begin
  5318.       NewLeftCol := LockedCols;
  5319.       for i := 0 to pred(Msg.Pos) do
  5320.         NewLeftCol := IncCol(NewLeftCol, 1);
  5321.       if (NewLeftCol <> LeftCol) then
  5322.         LeftCol := NewLeftCol;
  5323.     end;
  5324.   {------}
  5325.   begin
  5326.     {ignore SB_ENDSCROLL and SB_THUMBTRACK messages (the latter
  5327.      if required to by the Options property): this'll possibly
  5328.      avoid multiple validations}
  5329.     if (Msg.ScrollCode = SB_ENDSCROLL) or
  5330.        ((Msg.ScrollCode = SB_THUMBTRACK) and
  5331.         (not (otoThumbTrack in Options))) then
  5332.       begin
  5333.         inherited;
  5334.         Exit;
  5335.       end;
  5336.     {if not focused then do so; if being designed update the
  5337.      table view}
  5338.     if (otsUnfocused in tbState) then
  5339.       SetFocus
  5340.     else if (otsDesigning in tbState) then
  5341.       Update;
  5342.     {check to see whether the cell being edited is valid;
  5343.      no scrolling allowed if it isn't (tough).}
  5344.     if InEditingState then
  5345.       begin
  5346.         if not tbActCell.CanSaveEditedData(true) then
  5347.           Exit;
  5348.       end;
  5349.     {process the scrollbar message}
  5350.     case Msg.ScrollCode of
  5351.       SB_LINELEFT      : ProcessScrollBarClick(otsbHorizontal, scLineUp);
  5352.       SB_LINERIGHT     : ProcessScrollBarClick(otsbHorizontal, scLineDown);
  5353.       SB_PAGELEFT      : ProcessScrollBarClick(otsbHorizontal, scPageUp);
  5354.       SB_PAGERIGHT     : ProcessScrollBarClick(otsbHorizontal, scPageDown);
  5355.       SB_THUMBPOSITION : ProcessThumb;
  5356.       SB_THUMBTRACK    : if (otoThumbTrack in Options) then ProcessThumb;
  5357.     else
  5358.       inherited;
  5359.       Exit;
  5360.     end;
  5361.     Msg.Result := 0;
  5362.   end;
  5363. {--------}
  5364. procedure TOvcCustomTable.WMKeyDown(var Msg : TWMKey);
  5365.   var
  5366.     Cmd           : word;
  5367.     ShiftFlags    : byte;
  5368.   begin
  5369.     inherited;
  5370.  
  5371.     {If Tab key is being converted to arrow key, do it}
  5372.     if (otoTabToArrow in Options) and (Msg.CharCode = VK_TAB) then
  5373.       begin
  5374.         {get shift value}
  5375.         ShiftFlags := GetShiftFlags;
  5376.         {convert Tab combination to command}
  5377.         if (ShiftFlags = 0) then
  5378.           Cmd := ccRight
  5379.         else if (ShiftFlags = ss_Shift) then
  5380.           Cmd := ccLeft
  5381.         else
  5382.           Cmd := ccNone;
  5383.       end
  5384.     {If Enter key is being converted to right arrow, do it.}
  5385.     else if (otoEnterToArrow in Options) and (Msg.CharCode = VK_RETURN) then
  5386.       begin
  5387.         {get shift value}
  5388.         ShiftFlags := GetShiftFlags;
  5389.         {convert Enter combination to command}
  5390.         if (ShiftFlags = 0) then
  5391.           Cmd := ccRight
  5392.         else
  5393.           Cmd := ccNone;
  5394.       end
  5395.     {Otherwise just translate into a command}
  5396.     else
  5397.       Cmd := Controller.EntryCommands.TranslateUsing([tbCmdTable^], TMessage(Msg));
  5398.  
  5399.     if InEditingState then
  5400.       begin
  5401.         if (not (otoAlwaysEditing in Options)) and
  5402.            ((Cmd = ccTableEdit) or (Msg.CharCode = VK_ESCAPE)) then
  5403.           begin
  5404.             if not StopEditingState(Msg.CharCode <> VK_ESCAPE) then
  5405.               begin
  5406.                 inherited;
  5407.                 Exit;
  5408.               end;
  5409.           end
  5410.       end
  5411.     else {not editing}
  5412.       if (Cmd = ccTableEdit) or
  5413.          ((Cmd > ccLastCmd) and (Cmd < ccUserFirst) and
  5414.           ((Msg.CharCode = VK_SPACE) or
  5415.            ((VK_0 <= Msg.CharCode) and (Msg.CharCode <= VK_DIVIDE)) or
  5416.             (Msg.CharCode >= $BA))) then
  5417.         begin
  5418.           PostMessage(Handle, ctim_StartEdit, 0, 0);
  5419.           if (Cmd <> ccTableEdit) then
  5420.             PostMessage(Handle, ctim_StartEditKey, Msg.CharCode, Msg.KeyData);
  5421.         end;
  5422.  
  5423.     tbIsKeySelecting := false;
  5424.     case Cmd of
  5425.       ccBotOfPage,   ccBotRightCell,
  5426.       ccDown,        ccEnd,
  5427.       ccFirstPage,   ccHome,
  5428.       ccLastPage,    ccLeft,
  5429.       ccNextPage,    ccPageLeft,
  5430.       ccPageRight,   ccPrevPage,
  5431.       ccRight,       ccTopLeftCell,
  5432.       ccTopOfPage,   ccUp            : MoveActiveCell(Cmd);
  5433.       ccExtendDown   : begin tbIsKeySelecting := true; MoveActiveCell(ccDown);      end;
  5434.       ccExtendEnd    : begin tbIsKeySelecting := true; MoveActiveCell(ccEnd);       end;
  5435.       ccExtendHome   : begin tbIsKeySelecting := true; MoveActiveCell(ccHome);      end;
  5436.       ccExtendLeft   : begin tbIsKeySelecting := true; MoveActiveCell(ccLeft);      end;
  5437.       ccExtendPgDn   : begin tbIsKeySelecting := true; MoveActiveCell(ccNextPage);  end;
  5438.       ccExtendPgUp   : begin tbIsKeySelecting := true; MoveActiveCell(ccPrevPage);  end;
  5439.       ccExtendRight  : begin tbIsKeySelecting := true; MoveActiveCell(ccRight);     end;
  5440.       ccExtendUp     : begin tbIsKeySelecting := true; MoveActiveCell(ccUp);        end;
  5441.       ccExtBotOfPage : begin tbIsKeySelecting := true; MoveActiveCell(ccBotOfPage); end;
  5442.       ccExtFirstPage : begin tbIsKeySelecting := true; MoveActiveCell(ccFirstPage); end;
  5443.       ccExtLastPage  : begin tbIsKeySelecting := true; MoveActiveCell(ccLastPage);  end;
  5444.       ccExtTopOfPage : begin tbIsKeySelecting := true; MoveActiveCell(ccTopOfPage); end;
  5445.       ccExtWordLeft  : begin tbIsKeySelecting := true; MoveActiveCell(ccWordLeft);  end;
  5446.       ccExtWordRight : begin tbIsKeySelecting := true; MoveActiveCell(ccWordRight); end;
  5447.       ccCopy  : DoClipboardCopy;
  5448.       ccCut   : DoClipboardCut;
  5449.       ccPaste : DoClipboardPaste;
  5450.     else
  5451.       if (Cmd >= ccUserFirst) then
  5452.         DoUserCommand(Cmd);
  5453.     end;
  5454.   end;
  5455. {--------}
  5456. procedure TOvcCustomTable.WMKillFocus(var Msg : TWMKillFocus);
  5457.   begin
  5458.     inherited;
  5459.  
  5460.     if (otsEditing in tbState) then
  5461.       begin
  5462.         Exit;
  5463.       end;
  5464.  
  5465.     AllowRedraw := false;
  5466.     try
  5467.       InvalidateCell(ActiveRow, ActiveCol);
  5468.       tbState := tbState - [otsFocused] + [otsUnfocused];
  5469.     finally
  5470.       AllowRedraw := true;
  5471.     end;{try..finally}
  5472.   end;
  5473. {--------}
  5474. procedure TOvcCustomTable.WMLButtonDblClk(var Msg : TWMMouse);
  5475.   var
  5476.     Row    : TRowNum;
  5477.     Col    : TColNum;
  5478.     Region : TOvcTblRegion;
  5479.   begin
  5480.     inherited;
  5481.     if not (otsDesigning in tbState) then
  5482.       begin
  5483.         Region := CalcRowColFromXY(Msg.XPos, Msg.YPos, Row, Col);
  5484.         if Region = (otrInMain) then
  5485.           begin
  5486.             PostMessage(Handle, ctim_StartEdit, Msg.Keys, longint(Msg.Pos));
  5487.             PostMessage(Handle, ctim_StartEditMouse, Msg.Keys, longint(Msg.Pos));
  5488.           end;
  5489.       end;
  5490.   end;
  5491. {--------}
  5492. procedure TOvcCustomTable.WMLButtonDown(var Msg : TWMMouse);
  5493.   var
  5494.     Row : TRowNum;
  5495.     Col : TColNum;
  5496.     Action : TOvcTblSelectionType;
  5497.     Region : TOvcTblRegion;
  5498.     R : TRect;
  5499.     P : TPoint;
  5500.     ShiftKeyDown : boolean;
  5501.     CtrlKeyDown  : boolean;
  5502.     AllowDrag    : boolean;
  5503.     WasUnfocused : boolean;
  5504.   begin
  5505.     inherited;
  5506.  
  5507.     {are we currently unfocused? if so focus the table}
  5508.     WasUnfocused := false;
  5509.     if (otsUnfocused in tbState) then
  5510.       begin
  5511.         WasUnfocused := true;
  5512.         AllowRedraw := false;
  5513.         try
  5514.           {note: by the time SetFocus returns WMSetFocus will have been called}
  5515.           SetFocus;
  5516.           {..to get round an MDI bug..}
  5517.           if not Focused then
  5518.             {$IFDEF Win32}
  5519.             Windows.SetFocus(Handle);
  5520.             {$ELSE}
  5521.             WinProcs.SetFocus(Handle);
  5522.             {$ENDIF}
  5523.         finally
  5524.           AllowRedraw := true;
  5525.         end;{try..finally}
  5526.       end;
  5527.  
  5528.     {are we currently showing a sizing cursor? if so the user wants to
  5529.      resize a column/row}
  5530.     if (otsShowSize in tbState) then
  5531.       begin
  5532.         tbState := tbState - [otsShowSize] + [otsSizing];
  5533.         if (otsDoingRow in tbState) then
  5534.           begin
  5535.             if (Msg.YPos >= tbRowNums^.Ay[tbSizeIndex].Offset+6) then
  5536.               tbSizeOffset := Msg.YPos;
  5537.             tbDrawSizeLine;
  5538.           end
  5539.         else {we're sizing a column}
  5540.           begin
  5541.             if (Msg.XPos >= tbColNums^.Ay[tbSizeIndex].Offset+6) then
  5542.               tbSizeOffset := Msg.XPos;
  5543.             tbDrawSizeLine;
  5544.           end;
  5545.         Exit;
  5546.       end;
  5547.  
  5548.     {are we currently showing a row/col move cursor? if so the user wants
  5549.      to move that row/col}
  5550.     if (otsShowMove in tbState) then
  5551.       begin
  5552.         tbState := tbState - [otsShowMove] + [otsMoving];
  5553.         {work out the row/column we're in}
  5554.         CalcRowColFromXY(Msg.XPos, Msg.YPos, Row, Col);
  5555.         if (otsDoingCol in tbState) then begin
  5556.           tbMoveIndex := tbFindColInx(Col);
  5557.           R.Left := ColOffset[Col];
  5558.           R.Right := MinI(ClientWidth, R.Left + Columns[Col].Width);
  5559.           R.Top := RowOffset[0];
  5560.           R.Bottom := RowOffset[1];
  5561.         end else begin{doing row}
  5562.           tbMoveIndex := tbFindRowInx(Row);
  5563.           R.Top := RowOffset[Row];
  5564.           R.Bottom := RowOffset[Row + 1];
  5565.           R.Bottom := MinI(ClientHeight, R.Top + Rows[Row].Height);
  5566.           R.Left := ColOffset[0];
  5567.           R.Right := ColOffset[1];
  5568.         end;
  5569.  
  5570.         R.TopLeft := ClientToScreen(R.TopLeft);
  5571.         R.BottomRight := ClientToScreen(R.BottomRight);
  5572.  
  5573.         P := ClientToScreen(Point(Msg.XPos, Msg.YPos));
  5574.  
  5575.         tbDrag := TOvcDragShow.Create(P.x, P.y, R, clBtnFace);
  5576.  
  5577.         tbMoveIndexTo := tbMoveIndex;
  5578.         tbDrawMoveLine;
  5579.         Exit;
  5580.       end;
  5581.  
  5582.     {are we focused and do we allow selections? if so be prepared to start or
  5583.      extend the current selection (note that AlwaysEditing will be false)}
  5584.     if (otsFocused in tbState) and (not (otoNoSelection in Options)) then
  5585.       begin
  5586.         {if we are editing a cell then stop editing it now (if possible)}
  5587.         if InEditingState then
  5588.           begin
  5589.             {$IFDEF Win32}
  5590.             Windows.SetFocus(tbActCell.EditHandle);
  5591.             {$ELSE}
  5592.             WinProcs.SetFocus(tbActCell.EditHandle);
  5593.             {$ENDIF}
  5594.           end;
  5595.         {get the state of the shift & ctrl keys}
  5596.         ShiftKeyDown := (Msg.Keys and MK_SHIFT) <> 0;
  5597.         CtrlKeyDown := (Msg.Keys and MK_CONTROL) <> 0;
  5598.         {calculate where the mouse button was pressed}
  5599.         Region := CalcRowColFromXY(Msg.XPos, Msg.YPos, Row, Col);
  5600.         case Region of
  5601.           otrInMain :
  5602.             {the mouse was clicked in the main area}
  5603.             begin
  5604.               AllowRedraw := false;
  5605.               try
  5606.                 AllowDrag := true;
  5607.                 {confirm the new active cell}
  5608.                 DoActiveCellMoving(ccMouse, Row, Col);
  5609.                 {if neither shift nor control are down, or control is
  5610.                  down on its own, we have to reset the anchor point}
  5611.                 if (not ShiftKeyDown) then
  5612.                   begin
  5613.                     if CtrlKeyDown then
  5614.                       Action := tstAdditional
  5615.                     else
  5616.                       begin
  5617.                         Action := tstDeselectAll;
  5618.                         {if the active cell hasn't changed (ie the user
  5619.                          clicked on the active cell, must start editing}
  5620.                         if (ActiveRow = Row) and (ActiveCol = Col) and
  5621.                            not WasUnfocused then
  5622.                           begin
  5623.                             PostMessage(Handle, ctim_StartEdit, 0, 0);
  5624.                             PostMessage(Handle, ctim_StartEditMouse,
  5625.                                         Msg.Keys, longint(Msg.Pos));
  5626.                             AllowDrag := false;
  5627.                           end;
  5628.                       end;
  5629.                     tbSetAnchorCell(Row, Col, Action);
  5630.                   end
  5631.                 {if the shift key is down then the user is either extending
  5632.                  the last selection only (control is up) or the last
  5633.                  selection in addition to the other selections (control is
  5634.                  down); extend the selection}
  5635.                 else {shift key is down}
  5636.                   begin
  5637.                     if CtrlKeyDown then
  5638.                       Action := tstAdditional
  5639.                     else
  5640.                       begin
  5641.                         Action := tstDeselectAll;
  5642.                         tbIsSelecting := true;
  5643.                       end;
  5644.                     tbUpdateSelection(Row, Col, Action);
  5645.                   end;
  5646.                 {now set the active cell}
  5647.                 tbSetActiveCellPrim(Row, Col);
  5648.               finally
  5649.                 AllowRedraw := true;
  5650.               end;{try..finally}
  5651.               {until we get a mouse up message we are selecting with
  5652.                the mouse (if we're allowed to, that is)}
  5653.               if (otoMouseDragSelect in Options) and AllowDrag then
  5654.                 tbState := tbState - [otsNormal] + [otsMouseSelect];
  5655.             end;
  5656.           otrInLocked :
  5657.             begin
  5658.               {the mouse was clicked on a locked cell}
  5659.               if InEditingState then
  5660.                 if not StopEditingState(true) then
  5661.                   Exit;
  5662.               AllowRedraw := false;
  5663.               try
  5664.                 if (otoRowSelection in Options) and (Row >= LockedRows) then
  5665.                   tbSelectRow(Row);
  5666.                 if (otoColSelection in Options) and (Col >= LockedCols) then
  5667.                   tbSelectCol(Col);
  5668.                 if (otoRowSelection in Options) and (otoColSelection in Options) and
  5669.                    (Row < LockedRows) and (Col < LockedCols) then
  5670.                   tbSelectTable;
  5671.               finally
  5672.                 AllowRedraw := true;
  5673.               end;{try..finally}
  5674.               if (otsNormal in tbState) then
  5675.                 DoLockedCellClick(Row, Col);
  5676.             end;
  5677.           otrInUnused :
  5678.             begin
  5679.               {clicking in the unused area deselects all selections}
  5680.               if InEditingState then
  5681.                 if not StopEditingState(true) then
  5682.                   Exit;
  5683.  
  5684.               {move to new location}
  5685.               if (Row = CRCFXY_RowBelow) then
  5686.                 Row := IncRow(pred(RowLimit), 0);
  5687.               if (Col = CRCFXY_ColToRight) then
  5688.                 Col := IncCol(pred(ColCount), 0);
  5689.  
  5690.               {if row or col should changed, notify and doit}  
  5691.               if (Col <> ActiveCol) or (Row <> ActiveRow) then begin
  5692.                 DoActiveCellMoving(ccNone, Row, Col);
  5693.                 tbSetAnchorCell(Row, Col, tstDeselectAll);
  5694.                 tbSetActiveCellPrim(Row, Col);
  5695.               end;
  5696.             end;
  5697.         end;{case}
  5698.         Exit;
  5699.       end;
  5700.  
  5701.     {are we focused? (and selections are not allowed)}
  5702.     if (otsFocused in tbState) then
  5703.       if ((tbState * [otsNormal, otsEditing, otsHiddenEdit]) <> []) then
  5704.         begin
  5705.           Region := CalcRowColFromXY(Msg.XPos, Msg.YPos, Row, Col);
  5706.           case Region of
  5707.             otrInMain :
  5708.               begin
  5709.                 if InEditingState then
  5710.                   {$IFDEF Win32}
  5711.                   Windows.SetFocus(tbActCell.EditHandle);
  5712.                   {$ELSE}
  5713.                   WinProcs.SetFocus(tbActCell.EditHandle);
  5714.                   {$ENDIF}
  5715.                 AllowRedraw := false;
  5716.                 try
  5717.                   DoActiveCellMoving(ccMouse, Row, Col);
  5718.                   if not (otoAlwaysEditing in Options) then
  5719.                     if (ActiveRow = Row) and (ActiveCol = Col) and
  5720.                            not WasUnfocused then
  5721.                       begin
  5722.                         PostMessage(Handle, ctim_StartEdit, 0, 0);
  5723.                         PostMessage(Handle, ctim_StartEditMouse,
  5724.                                     Msg.Keys, longint(Msg.Pos));
  5725.                       end;
  5726.                   tbSetActiveCellPrim(Row, Col);
  5727.                 finally
  5728.                   AllowRedraw := true;
  5729.                 end;{try..finally}
  5730.                 PostMessage(Handle, ctim_StartEditMouse,
  5731.                             Msg.Keys, longint(Msg.Pos));
  5732.               end;
  5733.             otrInLocked :
  5734.               if (otsNormal in tbState) then
  5735.                 DoLockedCellClick(Row, Col);
  5736.           end;{case}
  5737.           Exit;
  5738.         end;
  5739.   end;
  5740. {--------}
  5741. procedure TOvcCustomTable.WMLButtonUp(var Msg : TWMMouse);
  5742.   var
  5743.     Form    : TForm;
  5744.     ColNum  : TColNum;
  5745.     ColFrom : TColNum;
  5746.     ColTo   : TColNum;
  5747.     RowNum  : TRowNum;
  5748.     RowFrom : TRowNum;
  5749.     RowTo   : TRowNum;
  5750.     DoingCol: boolean;
  5751.   begin
  5752.     inherited;
  5753.  
  5754.     if tbDrag <> nil then begin
  5755.       tbDrag.Free;
  5756.       tbDrag := nil;
  5757.     end;
  5758.  
  5759.     if (otsMouseSelect in tbState) then
  5760.       begin
  5761.         {tbIsSelecting := false;}
  5762.         tbState := tbState - [otsMouseSelect] + [otsNormal];
  5763.         Exit;
  5764.       end;
  5765.  
  5766.     if (otsSizing in tbState) then
  5767.       begin
  5768.         tbDrawSizeLine;
  5769.         AllowRedraw := false;
  5770.         try
  5771.           if (otsDoingRow in tbState) then
  5772.             begin
  5773.               if (tbSizeOffset < tbRowNums^.Ay[tbSizeIndex].Offset+6) then
  5774.                 tbSizeOffset := tbRowNums^.Ay[tbSizeIndex].Offset+6;
  5775.               FRows.Height[tbRowNums^.Ay[tbSizeIndex].Number] :=
  5776.                  tbSizeOffset - tbRowNums^.Ay[tbSizeIndex].Offset;
  5777.             end
  5778.           else
  5779.             begin
  5780.               if (tbSizeOffset < tbColNums^.Ay[tbSizeIndex].Offset+6) then
  5781.                 tbSizeOffset := tbColNums^.Ay[tbSizeIndex].Offset+6;
  5782.               FCols[tbColNums^.Ay[tbSizeIndex].Number].Width :=
  5783.                  tbSizeOffset - tbColNums^.Ay[tbSizeIndex].Offset;
  5784.             end;
  5785.           tbState := tbState - [otsSizing, otsDoingRow, otsDoingRow] + [otsNormal];
  5786.           if (otsDesigning in tbState) then
  5787.             begin
  5788.               Form := TForm(GetParentForm(Self));
  5789.               if (Form <> nil) and (Form.Designer <> nil) then
  5790.                 Form.Designer.Modified;
  5791.             end;
  5792.           InvalidateTable;
  5793.         finally
  5794.           AllowRedraw := true;
  5795.         end;{try..finally}
  5796.       end;
  5797.  
  5798.     if (otsMoving in tbState) then
  5799.       begin
  5800.         tbDrawMoveLine;
  5801.         DoingCol := otsDoingCol in tbState;
  5802.         tbState := tbState - [otsMoving, otsDoingRow, otsDoingCol] + [otsNormal];
  5803.         if (tbMoveIndex <> tbMoveIndexTo) then
  5804.           begin
  5805.             AllowRedraw := false;
  5806.             try
  5807.               if DoingCol then
  5808.                 begin
  5809.                   ColFrom := tbColNums^.Ay[tbMoveIndex].Number;
  5810.                   ColTo := tbColNums^.Ay[tbMoveIndexTo].Number;
  5811.                   if (ColTo > ColFrom) then
  5812.                     for ColNum := ColFrom to pred(ColTo) do
  5813.                       Columns.Exchange(ColNum, succ(ColNum))
  5814.                   else
  5815.                     for ColNum := pred(ColFrom) downto ColTo do
  5816.                       Columns.Exchange(ColNum, succ(ColNum));
  5817.                   if ActiveCol = ColFrom then
  5818.                     ActiveCol := ColTo
  5819.                   else if (ColTo > ColFrom) then begin
  5820.                     if (ColFrom < ActiveCol) and (ActiveCol <= ColTo) then
  5821.                       ActiveCol := IncCol(ActiveCol, -1);
  5822.                   end
  5823.                   else begin
  5824.                     if (ColTo <= ActiveCol) and (ActiveCol < ColFrom) then
  5825.                       ActiveCol := IncCol(ActiveCol, +1);
  5826.                   end;
  5827.                 end
  5828.               else {doing rows}
  5829.                 begin
  5830.                   RowFrom := tbRowNums^.Ay[tbMoveIndex].Number;
  5831.                   RowTo := tbRowNums^.Ay[tbMoveIndexTo].Number;
  5832.                   if (RowTo > RowFrom) then
  5833.                     for RowNum := RowFrom to pred(RowTo) do
  5834.                       Rows.Exchange(RowNum, succ(RowNum))
  5835.                   else
  5836.                     for RowNum := pred(RowFrom) downto RowTo do
  5837.                       Rows.Exchange(RowNum, succ(RowNum));
  5838.                   if ActiveRow = RowFrom then
  5839.                     ActiveRow := RowTo
  5840.                   else if (RowTo > RowFrom) then begin
  5841.                     if (RowFrom < ActiveRow) and (ActiveRow <= RowTo) then
  5842.                       ActiveRow := IncRow(ActiveRow, -1);
  5843.                   end
  5844.                   else begin
  5845.                     if (RowTo <= ActiveRow) and (ActiveRow < RowFrom) then
  5846.                       ActiveRow := IncRow(ActiveRow, +1);
  5847.                   end;
  5848.                 end;
  5849.             finally
  5850.               AllowRedraw := true;
  5851.             end;{try..finally}
  5852.             if (otsDesigning in tbState) then
  5853.               begin
  5854.                 Form := TForm(GetParentForm(Self));
  5855.                 if (Form <> nil) and (Form.Designer <> nil) then
  5856.                   Form.Designer.Modified;
  5857.               end;
  5858.           end;
  5859.       end;
  5860.   end;
  5861. {--------}
  5862. procedure TOvcCustomTable.WMMouseMove(var Msg : TWMMouse);
  5863.   var
  5864.     Row : TRowNum;
  5865.     Col : TColNum;
  5866.     NewMoveIndexTo  : integer;
  5867.     Region : TOvcTblRegion;
  5868.     Action : TOvcTblSelectionType;
  5869.     P : TPoint;
  5870.   begin
  5871.     inherited;
  5872.  
  5873.     if tbDrag <> nil then begin
  5874.       P := ClientToScreen(Point(Msg.XPos, Msg.YPos));
  5875.       tbDrag.DragMove(P.x, P.y);
  5876.     end;
  5877.  
  5878.     if (otsMouseSelect in tbState) then
  5879.       begin
  5880.         Region := CalcRowColFromXY(Msg.XPos, Msg.YPos, Row, Col);
  5881.         if (Region = otrOutside) or (Region = otrInUnused) then
  5882.           begin
  5883.             if (Row = CRCFXY_RowAbove) then
  5884.               Row := IncRow(ActiveRow, -1)
  5885.             else if (Row = CRCFXY_RowBelow) then
  5886.               with tbRowNums^ do
  5887.                 Row := MinL(pred(RowLimit), succ(Ay[pred(Count)].Number));
  5888.             if (Col = CRCFXY_ColToLeft) then
  5889.               Col := IncCol(ActiveCol, -1)
  5890.             else if (Col = CRCFXY_ColToRight) then
  5891.               with tbColNums^ do
  5892.                 Col := MinI(pred(ColCount), succ(Ay[pred(Count)].Number));
  5893.           end
  5894.         else if (Region = otrInLocked) then
  5895.           begin
  5896.             if (Row < LockedRows) then
  5897.               Row := IncRow(ActiveRow, -1);
  5898.             if (Col < LockedCols) then
  5899.               Col := IncCol(ActiveCol, -1);
  5900.           end;
  5901.         DoActiveCellMoving(ccMouse, Row, Col);
  5902.         if (Row = ActiveRow) and (Col = ActiveCol) then
  5903.           Exit; {there's nothing to do, just moved within cell}
  5904.         if ((Msg.Keys and MK_CONTROL) <> 0) then
  5905.           Action := tstAdditional
  5906.         else
  5907.           begin
  5908.             Action := tstDeselectAll;
  5909.             tbIsSelecting := true;
  5910.           end;
  5911.         AllowRedraw := false;
  5912.         try
  5913.           tbUpdateSelection(Row, Col, Action);
  5914.           tbSetActiveCellPrim(Row, Col);
  5915.         finally
  5916.           AllowRedraw := true;
  5917.         end;{try..finally}
  5918.         Exit;
  5919.       end;
  5920.  
  5921.     if (otsSizing in tbState) then
  5922.       begin
  5923.         tbDrawSizeLine;
  5924.         if (otsDoingRow in tbState) then
  5925.           begin
  5926.             if (Msg.YPos >= tbRowNums^.Ay[tbSizeIndex].Offset+6) then
  5927.               tbSizeOffset := Msg.YPos;
  5928.           end
  5929.         else
  5930.           begin
  5931.             if (Msg.XPos >= tbColNums^.Ay[tbSizeIndex].Offset+6) then
  5932.               tbSizeOffset := Msg.XPos;
  5933.           end;
  5934.         tbDrawSizeLine;
  5935.         Exit;
  5936.       end;
  5937.  
  5938.     if (otsMoving in tbState) then
  5939.       begin
  5940.         CalcRowColFromXY(Msg.XPos, Msg.YPos, Row, Col);
  5941.         if (otsDoingCol in tbState) then
  5942.           begin
  5943.             if (Col >= LockedCols) then
  5944.               begin
  5945.                 NewMoveIndexTo := tbFindColInx(Col);
  5946.                 if (NewMoveIndexTo <> tbMoveIndexTo) then
  5947.                   begin
  5948.                     tbDrawMoveLine;
  5949.                     tbMoveIndexTo := NewMoveIndexTo;
  5950.                     tbDrawMoveLine;
  5951.                   end;
  5952.               end;
  5953.           end
  5954.         else {we're moving rows}
  5955.           begin
  5956.             if (Row >= LockedRows) then
  5957.               begin
  5958.                 NewMoveIndexTo := tbFindRowInx(Row);
  5959.                 if (NewMoveIndexTo <> tbMoveIndexTo) then
  5960.                   begin
  5961.                     tbDrawMoveLine;
  5962.                     tbMoveIndexTo := NewMoveIndexTo;
  5963.                     tbDrawMoveLine;
  5964.                   end;
  5965.               end;
  5966.           end;
  5967.       end;
  5968.   end;
  5969. {--------}
  5970. procedure TOvcCustomTable.WMNCHitTest(var Msg : TMessage);
  5971.   begin
  5972.     if (otsDesigning in tbState) then
  5973.       DefaultHandler(Msg)
  5974.     else
  5975.       inherited;
  5976.   end;
  5977. {--------}
  5978. procedure TOvcCustomTable.WMSetCursor(var Msg : TWMSetCursor);
  5979.   var
  5980.     CurMousePos  : TPoint;
  5981.     NewCursor    : HCursor;
  5982.     IsVert       : boolean;
  5983.     IsColMove    : boolean;
  5984.     OnGridLine   : boolean;
  5985.     InMoveArea   : boolean;
  5986.   begin
  5987.     {ignore non client hit tests, let our ancestor deal with it}
  5988.     if (Msg.HitTest <> HTCLIENT) then
  5989.       begin
  5990.         inherited;
  5991.         if ((tbState * [otsShowSize, otsShowMove]) <> []) then
  5992.           tbState := tbState - [otsShowSize, otsShowMove, otsDoingRow, otsDoingCol]
  5993.                              + [otsNormal];
  5994.         Exit;
  5995.       end;
  5996.  
  5997.     {if the table is unfocused or we are editing, let our ancestor deal with it}
  5998.     if (otsUnfocused in tbState) or InEditingState then
  5999.       begin
  6000.         inherited;
  6001.         Exit;
  6002.       end;
  6003.  
  6004.     {get the mouse cursor position in terms of the table client area}
  6005.     GetCursorPos(CurMousePos);
  6006.     CurMousePos := ScreenToClient(CurMousePos);
  6007.     {work out whether the cursor is over a grid line or on the column
  6008.      move area; take into account whether such definitions are allowed}
  6009.     OnGridLine := tbIsOnGridLine(CurMousePos.X, CurMousePos.Y, IsVert);
  6010.     if OnGridLine then
  6011.       if IsVert then
  6012.         OnGridLine := (not (otoNoColResizing in Options)) or
  6013.                       (otsDesigning in tbState)
  6014.       else
  6015.         OnGridLine := (not (otoNoRowResizing in Options)) or
  6016.                       (otsDesigning in tbState);
  6017.     InMoveArea := false;
  6018.     if (not OnGridLine) and
  6019.        ((otoAllowColMoves in Options) or (otoAllowRowMoves in Options) or
  6020.         (otsDesigning in tbState)) then
  6021.       begin
  6022.         InMoveArea := tbIsInMoveArea(CurMousePos.X, CurMousePos.Y, IsColMove);
  6023.         if InMoveArea then
  6024.           if IsColMove then
  6025.             InMoveArea := otoAllowColMoves in Options
  6026.           else
  6027.             InMoveArea := otoAllowRowMoves in Options;
  6028.       end;
  6029.     {now set the cursor}
  6030.     if InMoveArea then
  6031.       begin
  6032.         if IsColMove then
  6033.           begin
  6034.             NewCursor := tbColMoveCursor;
  6035.             tbState := tbState - [otsNormal, otsShowSize, otsDoingRow]
  6036.                                + [otsShowMove, otsDoingCol];
  6037.           end
  6038.         else {row move}
  6039.           begin
  6040.             NewCursor := tbRowMoveCursor;
  6041.             tbState := tbState - [otsNormal, otsShowSize, otsDoingCol]
  6042.                                + [otsShowMove, otsDoingRow];
  6043.           end;
  6044.       end
  6045.     else if OnGridLine then
  6046.       if IsVert then
  6047.         begin
  6048.           NewCursor := Screen.Cursors[crHSplit];
  6049.           tbState := tbState - [otsNormal, otsShowMove, otsDoingRow]
  6050.                              + [otsShowSize, otsDoingCol];
  6051.         end
  6052.       else
  6053.         begin
  6054.           NewCursor := Screen.Cursors[crVSplit];
  6055.           tbState := tbState - [otsNormal, otsShowMove, otsDoingCol]
  6056.                              + [otsShowSize, otsDoingRow];
  6057.         end
  6058.     else
  6059.       begin
  6060.         NewCursor := Screen.Cursors[Cursor];
  6061.         tbState := tbState - [otsShowMove, otsShowSize, otsDoingRow, otsDoingCol]
  6062.                            + [otsNormal];
  6063.       end;
  6064.     SetCursor(NewCursor);
  6065.  
  6066.     Msg.Result := 1;
  6067.   end;
  6068. {--------}
  6069. procedure TOvcCustomTable.WMSetFocus(var Msg : TWMSetFocus);
  6070.   begin
  6071.     inherited;
  6072.  
  6073.     if (otsEditing in tbState) then
  6074.       begin
  6075.         if tbEditCellHasFocus(Msg.FocusedWnd) then
  6076.           GetParentForm(Self).Perform(WM_NEXTDLGCTL, 1, 0)
  6077.         else
  6078.           {$IFDEF Win32}
  6079.           Windows.SetFocus(tbActCell.EditHandle);
  6080.           {$ELSE}
  6081.           WinProcs.SetFocus(tbActCell.EditHandle);
  6082.           {$ENDIF}
  6083.         Exit;
  6084.       end;
  6085.  
  6086.     if (otsFocused in tbState) then
  6087.       Exit;
  6088.  
  6089.     AllowRedraw := false;
  6090.     try
  6091.       InvalidateCell(ActiveRow, ActiveCol);
  6092.       tbState := tbState - [otsUnfocused] + [otsFocused];
  6093.     finally
  6094.       AllowRedraw := true;
  6095.     end;{try..finally}
  6096.   end;
  6097. {--------}
  6098. procedure TOvcCustomTable.WMVScroll(var Msg : TWMScroll);
  6099.   {------}
  6100.   procedure ProcessThumb;
  6101.     var
  6102.       Divisor : LongInt;
  6103.     begin
  6104.       if (Msg.Pos <> TopRow) then
  6105.         begin
  6106.           if RowLimit < (16*1024) then
  6107.             TopRow := Msg.Pos
  6108.           else if Msg.Pos = LockedRows then
  6109.             TopRow := LockedRows
  6110.           else
  6111.             begin
  6112.               Divisor := Succ(RowLimit div $400);
  6113.               if (Msg.Pos = RowLimit div Divisor) then
  6114.                 TopRow := pred(RowLimit)
  6115.               else
  6116.                 TopRow := Msg.Pos * Divisor;
  6117.             end;
  6118.         end;
  6119.     end;
  6120.   {------}
  6121.   begin
  6122.     {ignore SB_ENDSCROLL and SB_THUMBTRACK messages (the latter
  6123.      if required to by the Options property): this'll possibly
  6124.      avoid multiple validations}
  6125.     if (Msg.ScrollCode = SB_ENDSCROLL) or
  6126.        ((Msg.ScrollCode = SB_THUMBTRACK) and
  6127.         (not (otoThumbTrack in Options))) then
  6128.       begin
  6129.         inherited;
  6130.         Exit;
  6131.       end;
  6132.     {if we're not focused then do so; if we're being designed
  6133.      update the table view}
  6134.     if (otsUnFocused in tbState) then
  6135.       SetFocus
  6136.     else if (otsDesigning in tbState) then
  6137.       Update;
  6138.     {check to see whether the cell being edited is valid;
  6139.      no scrolling allowed if it isn't (tough).}
  6140.     if InEditingState then
  6141.       begin
  6142.         if not tbActCell.CanSaveEditedData(true) then
  6143.           Exit;
  6144.       end;
  6145.     {process the scrollbar message}
  6146.     case Msg.ScrollCode of
  6147.       SB_LINEUP        : ProcessScrollBarClick(otsbVertical, scLineUp);
  6148.       SB_LINEDOWN      : ProcessScrollBarClick(otsbVertical, scLineDown);
  6149.       SB_PAGEUP        : ProcessScrollBarClick(otsbVertical, scPageUp);
  6150.       SB_PAGEDOWN      : ProcessScrollBarClick(otsbVertical, scPageDown);
  6151.       SB_THUMBPOSITION : ProcessThumb;
  6152.       SB_THUMBTRACK    : if (otoThumbTrack in Options) then ProcessThumb;
  6153.     else
  6154.       inherited;
  6155.       Exit;
  6156.     end;
  6157.     Msg.Result := 0;
  6158.   end;
  6159. {====================================================================}
  6160.  
  6161.  
  6162. end.